Android 使用setExact()在每天的特定时间触发警报

Android 使用setExact()在每天的特定时间触发警报,android,alarmmanager,Android,Alarmmanager,我每天都试图在特定的时间触发一次警报。但像所有其他人一样,我使用的是setExact()而不是setRepeating()。警报在正确的时间触发。但一旦它开火,它每5秒就会重复一次。我怎样才能在一天中的特定时间触发它一次?这是我的密码: MainActivity.java: public class MainActivity extends AppCompatActivity implements Observer { private AlarmManager alarmManager

我每天都试图在特定的时间触发一次警报。但像所有其他人一样,我使用的是
setExact()
而不是
setRepeating()
。警报在正确的时间触发。但一旦它开火,它每5秒就会重复一次。我怎样才能在一天中的特定时间触发它一次?这是我的密码:

MainActivity.java:

public class MainActivity extends AppCompatActivity implements Observer {

    private AlarmManager alarmManager = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        BroadcastObserver.getInstance().addObserver(this);
    }

    @Override
    public void update(Observable o, Object arg) {
        Log.e("MainActivity", "Alarm set through observer");
        cancelAlarm();
        setAlarm();
    }

    @Override
    protected void onStart() {
        super.onStart();
        if (!checkAlarm()) {
            setAlarm();
        }

    }

    public void setAlarm() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 14);
        calendar.set(Calendar.MINUTE, 13);
        calendar.set(Calendar.SECOND, 0);
        alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        Intent intent = new Intent(this, MyReceiver.class);
        intent.setAction(MyReceiver.ACTION_RECEIVER);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 1001, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        alarmManager.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
    }

    private boolean checkAlarm() {
        Intent intent = new Intent(this, MyReceiver.class);
        intent.setAction(MyReceiver.ACTION_RECEIVER);
        boolean isSet = PendingIntent.getBroadcast(this, 1001, intent, PendingIntent.FLAG_NO_CREATE) != null;
        Log.e("MainActivity", isSet + " :Alarm is set");
        return isSet;
    }

    @Override
    protected void onStop() {
        super.onStop();
        cancelAlarm();
    }

    private void cancelAlarm() {
        Intent intent = new Intent(this, MyReceiver.class);
        intent.setAction(MyReceiver.ACTION_RECEIVER);
        final PendingIntent pendingIntent =
                PendingIntent.getBroadcast(MainActivity.this, 1001, intent,
                        PendingIntent.FLAG_NO_CREATE);
        if (pendingIntent != null) {
            alarmManager.cancel(pendingIntent);
            pendingIntent.cancel();
        }
    }
}
广播接收机:

public class MyReceiver extends BroadcastReceiver {

    public static final String ACTION_RECEIVER = "Receiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.e("MainActivity", "triggered");
        BroadcastObserver.getInstance().updateValue(intent);
    }
}
广播观察员:

public class BroadcastObserver extends Observable {
    private static BroadcastObserver instance = new BroadcastObserver();

    public static BroadcastObserver getInstance(){
        return instance;
    }

    private BroadcastObserver(){}

    public void updateValue(Object data) {
        synchronized (this) {
            setChanged();
            notifyObservers(data);
        }
    }
}
一旦它开火,它每5秒就会重复一次

您正在将给定日期的闹钟设置为14:13。当警报触发时,将通知观察者,并设置完全相同的警报(14:13)

此时我们已经过了14:13,因此警报将立即触发,再次通知观测者,导致上述步骤的无限循环

最简单的解决方案可能是在设置警报时检查时间,如果是过去,则在警报中添加一天:

Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 14);
calendar.set(Calendar.MINUTE, 13);
calendar.set(Calendar.SECOND, 0);

if (calendar.before(Calendar.getInstance())) {
    calendar.add(Calendar.DAY_OF_YEAR, 1);
}
为避免内存泄漏,您需要在适当的时候移除
观察者

@Override
protected void onDestroy() {
    BroadcastObserver.getInstance().deleteObserver(this);
    super.onDestroy();
}

此外,取消
update()
中的报警也是多余的。这不是重复报警,因此在报警触发后取消报警是没有意义的。

为什么每天都取消并设置报警?您是否应该使用setRepeating每天重复?
setRepeating()
更倾向于优化,它可能在达到特定目标后随时触发。因此,触发警报并不那么准确。这是我在书中看到的。请发布
BroadcastObserver
的代码@地球人吉姆