何时注册/注销在活动中创建的广播接收器?

83

我需要在一个活动的onCreate事件中创建一个自定义广播接收器,显然我需要在活动的onDestroy事件中取消注册广播接收器。

为了清晰起见,这是我使用的代码片段

public class AnActivity extends Activity {
    private ResponseReceiver receiver;

    public class ResponseReceiver extends BroadcastReceiver {
           public static final String ACTION_RESP =
              "mypackagename.intent.action.MESSAGE_PROCESSED";

           @Override
            public void onReceive(Context context, Intent intent) {
// TODO Start a dialogue if message indicates successfully posted to server
            }
    }   

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        IntentFilter filter = new IntentFilter(ResponseReceiver.ACTION_RESP);
        filter.addCategory(Intent.CATEGORY_DEFAULT);
        receiver = new ResponseReceiver();
        registerReceiver(receiver, filter);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        unregisterReceiver(receiver);
    }

我读过在活动的onPause/onResume和onStart/onStop事件中应该注册和取消注册广播接收器。

我真的很想了解什么被认为是最佳实践以及为什么。


这是因为当 onDestroy() 被调用时,接收者将不再监听任何事件。 - billa-code
5个回答

94

你应该在 onStart()onStop() 中注册和注销广播接收器。

Activity注册BroadcastReceiver的唯一原因是在当前活动中使用事件,以通知用户事件的发生。如果已经调用了onStop(),则Activity不再处于前台,因此无法更新用户。

如果您想在后台接收广播事件,请考虑使用服务,如此处所示here

正如Konstantin所说,不能保证会调用onDestroy(),并且当Activity不再打开时,您可能会继续接收广播。


3
你是在建议我应该在 onResume 中注册而不是在 onCreate 中注册,还是说两个方法都需要注册?当创建一个活动时,onResume 方法是否总是被调用? - jamesc
9
你应该在 onResume() 方法中进行注册。无论何时显示一个 Activity,都会调用 onResume() 方法(它是 Activity 出现之前的最后一个方法)(http://developer.android.com/reference/android/app/Activity.html) 如果你只在 onCreate() 方法中注册,并在 onPause() 方法中取消注册,那么下次将该 Activity 切换到前台时,onCreate() 不会再被调用,因此也就不会重新注册接收器。是的,我是指要“替代”在 onCreate() 中注册接收器,而不是同时在 onCreate() 和 onResume() 中注册。 - SnowyTracks
1
@SnowyTracks:你能否评论一下为什么在onResume/onPause中执行BroadcastReceiver注册调用比在onStart/onStop中执行更可取?在查看绑定服务的开发人员指南时,我发现了这个链接。在该部分的末尾,建议在onStart/onStop中执行服务绑定/解绑(出于性能原因)。我想知道这是否也适用于BroadcastReceivers?提前致谢。 - Janus Varmarken
1
@jvmk同意,Android文档建议在onStart和onStop中执行此操作。我认为在99%的情况下,这几乎没有什么区别,只有在使用对话框活动或部分前台活动时才会有行为上的差异。但是我将更新我的答案以符合Android文档。 - SnowyTracks
1
我看到你昨天编辑了第二段...感谢你为了更一致的答案而做出的努力。但它仍然没有解释为什么应该使用onStart/onStop 而不是或与onResume/onPause结合使用,这是OP的问题。相反,第二段的解释对于onResume/onPause和onStart/onStop同样适用:一旦调用了onPause,活动就不再处于前台。所以我们没有你建议的“为什么”。 - LarsH
显示剩余3条评论

19

由于不能保证onDestroy()会被调用,因此您应该使用onPause()进行注销。考虑您的广播接收器的生命周期:您是否需要它仅在您的活动位于前台时才处于活动状态?然后请使用onResume()/onPause()


如果应用程序在后台运行,但我们仍然需要更新活动中的内容,因为用户可能会恢复应用程序并显示更新的数据,该怎么办? - Usman Rana

11

Android文档并没有规定一个单独的地方来注册/注销广播接收器,但是它提到onStart()/onStop()onResume()/onPause()都可以作为可能的选择。

做出这个决定的最大因素是,你的接收器需要在什么时候能够完成其工作?这将决定何时注册和注销它。

  • 当活动处于焦点状态时,接收器是否需要对广播进行操作?如果是,则可以在onPause()/onReceive()中注册/注销它。(您也可以使用更长的生命周期,如onStart()/onStop(),但是然后您应该在接收器的onReceive()期间检查活动是否处于焦点状态。)

  • 即使没有焦点(例如显示对话框时),接收器是否需要在可见时执行某些操作?如果是,则使用onStart()/onStop()(或更长的生命周期,但是接收器的onReceive()应检查活动是否可见)。

  • 即使活动不可见,接收器是否仍需了解广播的情况?例如,它是否需要记住发生了什么事情,以便当活动变为可见时,可以反映结果状态?那么您需要使用onCreate()/onDestroy()来注册/注销。(请注意,还有其他实现此类功能的方法。)

如果你在onStart()中注册了,就不要在onResume()中再次注册,因为这是多余的:onResume()在没有先调用onStart()的情况下不会被调用。
还要记住,最好尽量使onPause()轻量化

onPause()执行非常简短,并且不一定提供足够的时间来执行保存操作。因此,您不应该使用onPause()来保存应用程序或用户数据,进行网络调用或执行数据库事务;这样的工作可能无法在方法完成之前完成。相反,您应该在onStop()期间执行重负载关闭操作。

onDestroy()确实不能保证被调用,如果系统杀死进程以节省内存。但是如果进程被杀死,进程将无法接收广播。在这种情况下,注销广播接收器是否真的有必要呢?

感谢您回答我的问题,但是您的回答有些混淆人心,也不是严格准确的。您说“如果您在onStart()中注册,请不要在onPause()中再次注册,因为那样会是多余的:onPause()永远不会在没有先调用onStart()的情况下被调用。”这种说法只是不合逻辑和令人困惑的,尤其是当已经有一个完全准确的答案被接受时。 - jamesc
@jamesc:糟糕,我是指onResume而不是onPause。你说得对,那确实有点令人困惑。现在已经修复了。至于被接受的答案,我已经发表了评论。我认为这个答案提供了重要且相关的信息,而被接受的答案则没有提供。 - LarsH

5

Android系统在不调用onStop()方法的情况下可能会杀死您的应用程序。解决这种情况的最佳方法是在onResume()方法中注册BroadcastReceiver,并在onPause()方法中取消注册。


1
我也在做这个。onStop() 也遇到了问题。 - Vygintas B

0

在onResume()和onPause()方法中注册和注销广播。

如果你在onStart()中注册,在onStop()中注销,那么你会遇到以下问题。

如果你的设备屏幕被锁定,那么onStop()会被调用,如果你解锁时onStart()不会被调用。这就是为什么你需要在onResume()和onPause()方法中注册和注销它的原因。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接