【问题标题】:cancelling an alarm after program crash程序崩溃后取消警报
【发布时间】:2012-01-17 13:54:00
【问题描述】:

我有一个后台服务,它设置一个重复的警报,完成它的任务并自行停止。然后,当闹钟唤醒时,它会再次启动服务。如果程序崩溃,警报仍然存在并唤醒警报广播接收器。有没有办法在崩溃时取消警报 - 我想我可以从任何捕获的异常中取消警报,但其他原因呢?

或者当警报广播接收器被触发时,有什么方法可以判断设置它的程序是否崩溃了?

【问题讨论】:

    标签: android


    【解决方案1】:

    活动生命周期可以通过使用onDestroy() 回调中的isFinishing() 函数检测“意外”终止的干净完成。您可以将其添加到应用中的每个活动中:

    protected void onDestroy () {
        boolean crashedOnLastClose = false;
    
        if (!isFinishing()) {
            // The application is being destroyed by the O/S
            crashedOnLastClose = true;
    
            // Store the result somewhere for the BroadcastReceiver to check later
            SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
            SharedPreferences.Editor editor = settings.edit();
            editor.putBoolean("crashedOnLastClose", crashedOnLastClose);
            editor.commit();
        }
    }
    

    然后在您的 BroadcastReceiver 中,从 SharedPreferences 框架(或您决定存储它的任何地方)拉回结果,如果值为 true,则取消操作:

    public class MyAlarmReceiver extends BroadcastReceiver {
    
        public void onReceive(Context context, Intent intent) {
            SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
            boolean crashedOnLastClose = settings.getBoolean("crashedOnLastClose", false);
    
            if (!crashedOnLastClose) {
                // No crash on last run, handle the alarm
                // ...
            }
        }
    }
    

    记得在下次启动时将其重置为 false!应该这样做:

    protected void onCreate (Bundle savedInstanceState) {
        // Make sure this always resets to FALSE on launch
        SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
        SharedPreferences.Editor editor = settings.edit();
        editor.putBoolean("crashedOnLastClose", false);
        editor.commit();
    }
    

    这应该捕获您的崩溃事件;但请记住,当您的应用程序被强制关闭时,它还会检测其他时间 - 例如设备上的内存不足。要区分这些类型的事件,您需要检查系统状态以及 isFinishing()

    编辑 - 服务

    您的服务有一个单独的生命周期,您必须将其视为一个单独的应用程序。正如您所注意到的,这里没有“isFinishing()”,但服务实际上非常简单,因为它们只被您的代码干净地终止,您可以很容易地捕获它。

    在您的服务中,添加一个新的布尔值(可能称为“isFinishing”)并在您的服务完成时将其设置为 true。然后也覆盖 onDestroy() 并添加一个类似于我为您的活动描述的检查:

    protected void onDestroy () {       
        // Store the result somewhere for the BroadcastReceiver to check later
        SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
        SharedPreferences.Editor editor = settings.edit();
        editor.putBoolean("crashedOnLastClose", !isFinishing);
        editor.commit();
    }
    

    然后广播接收器将使用我们之前添加的相同代码来检测服务或活动是否崩溃。

    【讨论】:

    • 不错。我看到的缺点是每个活动/服务都应该添加此代码。而且这种方法不适用于 ContentProviders。
    • 谢谢肖恩,我会试试的。由于内存不足,应用程序是否可以在警报之间强制关闭?如果它已经关闭并且确实关闭了,警报会再次唤醒它还是低内存关闭会破坏警报广播接收器?我想知道是什么机制使警报广播接收器可用 - 假设详细信息保存在底层操作系统中以便启动。
    • @inazaruk 一些优点。人们经常通过扩展一个共享的抽象类来在活动之间共享代码,所以对于某些人来说,重复是很简单的。可能需要其他东西来分析 ContentProvider 生命周期。
    • @ron 您的应用只有在运行时才有资格终止,而不管您的警报是如何安排的。 AlarmProvider 源代码就像一个全局调度程序,如果它处于“停止”状态,它将启动您的应用程序以执行您的 BroadcastReceiver。
    • @Sean 以及在 onDestroy() 中使用 isFinishing() 在两个活动中我需要在服务中使用它。 isFinishing 在活动中可以,但我无法弄清楚如何在服务中对其进行编码。我试过了:-
    猜你喜欢
    • 1970-01-01
    • 2020-03-13
    • 1970-01-01
    • 1970-01-01
    • 2021-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-22
    相关资源
    最近更新 更多