【问题标题】:Unable to cancel repeating alarm Android无法取消重复警报Android
【发布时间】:2015-03-17 15:18:22
【问题描述】:

我已阅读有关 Android、AlarmManager 和取消的所有问题。

我目前使用Activity 通过以下方式启动接收器:

long msInterval = 1;
Intent intent = new Intent(this, Updater.class);
intent.setAction("theAction");

PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 12, intent, 0);
Updater.origin = pendingIntent;

AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (msInterval), msInterval, pendingIntent);

这会在调用此代码一毫秒后启动接收器Updater,请求代码为 12(任意选择,使用 0 会产生相同的错误行为)。它还将 Updater 的来源设置为当前调度的 PendingIntent,稍后用于取消警报。

更新程序如下所示:

public class Updater extends BroadcastReceiver {

    public static int flaggedClose = 0;
    public static PendingIntent origin;

    @Override
    public void onReceive(Context context, Intent intent) {
        // Do some work
        Log.w("running", "run");

        if (Updater.flaggedClose != 0) {
            if(flaggedClose == 1) {
                Toast.makeText(context, "Finished!", Toast.LENGTH_SHORT).show();
            }
            flaggedClose++; // Only show Toast once
            Log.w("running", "close");

            origin.cancel();
            AlarmManager alarms = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
            alarms.cancel(origin);
        }
    }
}

目前它所做的只是记录消息“运行”,它完成了约 1000 次/秒。当调用Activity的onStop()时,Updater.flaggedClose被设置为1。我可以在 Logcat 中看到这一点,因为它开始打印日志警告“关闭”。但是,警报仍然存在,因此所有其他记录的消息都是“运行”,而其他所有消息都是“关闭”。在最好的情况下,警报会在几秒钟后关闭。最坏的情况我需要重新启动手机。在 AlarmManager 的描述中,它特别指出 close 关闭“任何类型的警报,其 Intent 与此匹配(由 filterEquals(Intent) 定义),将被取消”。为什么还会触发警报?

【问题讨论】:

  • 闹钟没有取消是什么意思?
  • @apurva:警报仍在触发中。我希望它会记录一次“关闭”,然后alarms.cancel(origin); 会取消所有警报,因此不会记录更多消息。现在我可以看到至少还有 100 多条记录的消息,这意味着肯定还有 100 多条警报响起。
  • @Pphoenix 您能否将警报间隔增加到更大的值(用于测试目的)? 1ms 相当短,我想知道,在取消发生之前是否已经触发了这 100 个“额外”警报。我不确定AlarmManager 是否适合您的用例。 developer.android.com/reference/android/app/AlarmManager.html阅读粗体的注释
  • @ci_ 我跑了 20 毫秒,它工作得更好,虽然我还有一些额外的东西。就像你说的,问题可能是 cancel 之前的代码需要 1 毫秒或更长时间,因此永远不会执行取消,或者在两者之间安排更多警报。我会调查Handler
  • @ci_ 你说的没错,警报的创建速度比取消警报的速度快!

标签: android alarmmanager repeatingalarm receiver


【解决方案1】:

正如 ci_ 在 cmets 中提到的,有可能“在取消发生之前已经触发了 100 个“额外”警报”。对于其他有同样问题的人,这里有一个解决方案。我测试了 AlarmManager,如果你有至少 200 毫秒的延迟,它似乎效果最好。要获得更低的延迟,请使用Handler。使用 Handler 的问题示例:

public class MainActivity extends Activity {

    private boolean pressed = false;
    private boolean done = false;
    private Handler worker;
    private Runnable method;
    long msInterval = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        worker = new Handler();
        method = getMethod();

        Button toggle = (Button)(findViewById(R.id.toggle));
        toggle.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                if(!pressed) {
                    worker.post(method);
                    pressed = true;
                } else {
                    done = true;
                }
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        done = true;
    }

    private Runnable getMethod() {
        return new Runnable() {
            public void run() {
                Log.w("running", "run");
                if (done) {
                    Toast.makeText(getApplicationContext(), "Finished!", Toast.LENGTH_SHORT).show();
                    Log.w("running", "close");
                } else {
                    worker.postDelayed(method, msInterval);
                }
            }
        };
    }
}

在按下第一个按钮时,处理程序会启动可运行对象,并且在每次调用时,可运行对象都会调用自身。在第二个按钮按下条件done 设置为 true,因此可运行对象在一轮(清理)后完成。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多