onPause中的unregisterReceiver(receiver)导致接收器无法注册

时间:2019-04-16 14:36:56

标签: java android android-intent broadcastreceiver

您好,溢出者。我的BroadcastReciever出现了问题-我知道存在很多问题和答案,因为在过去的两天里我一直在尝试每个问题和答案,因此,如果您要将此代码标记为重复检查,请确保代码没有不符合我已经写的内容(因为我几乎可以肯定地将它复制成一个SO答案)。

所以我们开始:

我想检测基本活动中锁定屏幕的打开或关闭状态-我所有其他活动都将从该锁定屏幕扩展

public abstract class BaseActivity extends AppCompatActivity{////

在这里我有成员变量

BroadcastReceiver receiver;
IntentFilter filter;

我这样分配的:

receiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    if (intent.getAction() != null && intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
                        //do some code
                    } else {
                       //do something else
                    }
                }
            };


filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);

如果我将其放在onCreate()onResume()中,它将按预期工作,并且我可以在创建或恢复中成功调用registerReceiver(receiver, filter),并且效果很好。

我不希望在暂停应用程序时启用此功能,因此所有答案和教程都建议我在onPause上取消注册

     @Override
        protected void onPause() {
//I have commented both out to demonstrate that I have tried both before and after the calling the superclass
      //    this.unregisterReceiver(receiver);
            super.onPause();
    //      unregisterReceiver(receiver);

        }

当我包含此取消注册呼叫时,它将停止注册。我尝试在onCreate,onResume和两者中进行注册。我可以在整个活动中随意组合,但是一旦引入取消注册,它就根本不起作用-甚至没有错误或崩溃(否则我将在此处包括堆栈跟踪)。

我能够实现的关闭目标是:

receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
  if (intent.getAction() != null && intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
  //do some code 
  unregisterReceiver(receiver);

通过将取消注册放入onRecieve中,我可以注销接收器并正确地重新注册它,除了如果我的应用程序在堆栈中有多个活动,我会收到内存泄漏错误和跟踪请求,而不是如果我忘了添加一个取消注册呼叫,请惠顾。

所以有人知道为什么将取消注册调用添加到onPause()会导致接收方完全取消吗?

2 个答案:

答案 0 :(得分:1)

我认为您遇到了这个问题,因为系统在onStop()方法之后发送了ACTION_SCREEN_OFF,因此您无法处理它,因为您已经取消了注册。不知道为什么您不能处理SCREEN_ON事件,因为当我对此进行测试时,我看到该系统在onResume()之后发送它。这是我的日志中的内容:

D/TEST: onPause:
D/TEST: onStop:
D/TEST: onReceive: action = android.intent.action.SCREEN_OFF
D/TEST: onStart:
D/TEST: onResume:
D/TEST: onReceive: action = android.intent.action.SCREEN_ON

我认为,它是在onResume被调用之前发送的,但在发送之后被发送了。

因此,我的解决方案是在onCreate(@Nullable Bundle savedInstanceState)中注册接收者,然后在onDestroy()中取消注册,这就是我获得此日志的方式。

更新1:这就是我在onCreate(@Nullable Bundle savedInstanceState)

中注册接收者的方式
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(new TestReceiver(), filter);

更新2:我想念的是,如果您的活动暂停,则不需要接收事件。如果有一些代码在活动暂停时不想执行,我建议您创建一个简单的枚举:

枚举ActivityState {     已开始,已恢复,已暂停,已停止 }

和私有变量ActivityState currentState。然后,在生命周期中,方法将适当的状态分配给currentState。然后,在接收方onReceive()方法中,您可以检查当前状态并根据状态执行所需操作。 在应用程序处于活动状态时进行记录:

D/TEST: onReceive: action = android.intent.action.SCREEN_OFF, current Activity state = STOPED
D/TEST: onReceive: action = android.intent.action.SCREEN_ON, current Activity state = RESUMED

并记录应用未激活的时间:

D/TEST: onReceive: action = android.intent.action.SCREEN_OFF, current Activity state = STOPED
D/TEST: onReceive: action = android.intent.action.SCREEN_ON, current Activity state = STOPED

希望对您有所帮助!

答案 1 :(得分:1)

我建议延迟取消注册一段时间,我尝试了1秒钟,并且可以正常工作。

override fun onResume() {
    super.onResume()

    registerReceiver(broadcast, IntentFilter().apply {
        addAction(Intent.ACTION_SCREEN_ON)
        addAction(Intent.ACTION_SCREEN_OFF)
    })
}


override fun onPause() {
    super.onPause()

    Handler().postDelayed({
        unregisterReceiver(broadcast)
    }, 1000)
}