Java 注销在活动上下文中注册的BroadcastReceiver将导致IllegalArgumentException崩溃

Java 注销在活动上下文中注册的BroadcastReceiver将导致IllegalArgumentException崩溃,java,android,broadcastreceiver,Java,Android,Broadcastreceiver,这次撞车很奇怪 在onStart中,注册存储在活动字段中的BroadcastReceiver。在顶部中,此BroadcastReceiver未注册。当BroadcastReceiver成功注册时,我还将isRegistered字段设置为true,在注销接收器之前,我检查该字段以查看是否需要 然而,在Crashlytics中,我看到有时会失败,整个应用程序会崩溃,出现IllegalArgumentException和Receiver not registered消息,该消息源于android.ap

这次撞车很奇怪

onStart
中,注册存储在活动字段中的BroadcastReceiver。在顶部中,此BroadcastReceiver未注册。当BroadcastReceiver成功注册时,我还将
isRegistered
字段设置为
true
,在注销接收器之前,我检查该字段以查看是否需要

然而,在Crashlytics中,我看到有时会失败,整个应用程序会崩溃,出现
IllegalArgumentException
Receiver not registered
消息,该消息源于
android.app.LoadedApk#forgetReceiverDispatcher
。这很奇怪,考虑到我检查了国旗,对吗

在我研究了处理注册/注销的
ContextImpl
LoadedApk
类并添加了一些基于反射的诊断之后,它变得更加神秘。简而言之,在每次这样的崩溃中,我将提取现有
上下文
广播接收器
的映射(请参阅和)

当它正常注销时,不会发生崩溃,我可以看到这样的地图:

com.mypackage.myapp.MyAppContext instance -> list of instances that are registered app wide
com.mypackage.myapp.MyActivity1 instance -> list of instances that are registered for Activity1
com.mypackage.myapp.MyActivity2 instance -> list of instances that are registered for Activity2
...
com.mypackage.myapp.MyAppContext instance -> list of instances that are registered app wide
但是,在发生碰撞时,此地图如下所示:

com.mypackage.myapp.MyAppContext instance -> list of instances that are registered app wide
com.mypackage.myapp.MyActivity1 instance -> list of instances that are registered for Activity1
com.mypackage.myapp.MyActivity2 instance -> list of instances that are registered for Activity2
...
com.mypackage.myapp.MyAppContext instance -> list of instances that are registered app wide
i、 e.没有注册我的
BroadcastReceiver
的活动,即使我从未调用过
unregisterReceiver

它只发生在一个特定的活动中,所以我的第一个猜测是,该活动以某种方式泄漏,
onDestroy
生命周期被调用,活动条目从接收者映射中删除,然后当我们试图注销它时,接收者显然不在那里。但是,如果是这种情况,那么为什么在
ondestory
之后调用
onStop
?那么为什么接收者列表完全是空的呢

如果不是泄漏,那么什么会导致这种令人费解的行为呢?我真的希望有人经历过这样一件奇怪的事情,也许能帮助我,因为现在我完全没有主意了

在onStart中,存储在“活动”字段中的BroadcastReceiver是 注册的。在onStop中,此BroadcastReceiver未注册

onPause
状态下可能会发生很多事情。应用程序进程可能会被终止,并可能在创建时再次启动

引述

要停止接收广播,请拨打 unregisterReceiver(android.content.BroadcastReceiver)。一定要 当不再需要接收器或上下文不可用时,取消注册接收器 不再有效

请注意您注册和注销接收人的位置,例如 例如,如果使用 活动的上下文,您应该在onDestroy()中注销它以防止 将接收器从活动上下文中泄漏。如果你注册了 在onResume()中,您应该在onPause()中将其注销以 防止多次注册(如果您不想收到 暂停时广播,这可以减少不必要的系统开销 开销)。不要在onSaveInstanceState(捆绑包)中注销,因为 如果用户在历史堆栈中向后移动,则不会调用此函数

因此,请分别在
onResume
onPause
中注册和注销


如果这能解决问题,请告诉我:)

已编辑

就说我感觉到了疼痛。为了解决我自己的问题,我刚刚找到了一个解决方案,但是,为了回答你的问题,我真的深入研究了文档,所以以前的问题甚至自己编写了简单的代码并检查了一些生命周期测试(在这些测试中,我认为我找到了错误的答案)。我找不到发生此事件的原因,但要解决此问题,我建议将注册/取消注册包装在try-catch块中:

private void registerBroadcastReceiver() {
    try {
        appUpdateReceiver = new AppUpdateReceiver();
        registerReceiver(appUpdateReceiver, appUpdateIntentFilter);
    } catch (IllegalArgumentException e) {
        // already registered
    }
}

private void unRegisterBroadCastReceiver() {
    try {
        unregisterReceiver(appUpdateReceiver);
    } catch (IllegalArgumentException e) {
        // already unregistered
    }
}

请提供一些代码,以便社区能够更深入地研究这一问题。感谢您提到LoadedAppk类

您是否在任何时候将
isRegistered
读写到主应用程序线程以外的其他线程,例如在主应用程序线程未执行的回调中?如果是这样,由于可能存在内存一致性错误,这可能会导致读取过时的值和其他奇怪的行为。如果内存一致性被破坏,可能会出现非常奇怪的行为,例如,请参见和。另外,是否在主应用程序线程中注册
广播接收器

您是否尝试过以各种方式检查生命周期,以查看您是否可以自己复制缺陷,例如将手机转向另一侧并以这种方式导致生命周期更改,或者以其他方式强制生命周期更改

在调用
unregisterReceiver
后,是否将
isRegistered
设置为false?我想知道这是否相关,例如,如果调用了
onStart
,注册成功,调用了later
onStop
,取消注册成功,调用later
onStart
但注册不成功,然后调用
onStop
,尽管由于未重置
isRegistered
而未注册任何
BroadcastReceiver
。我不知道这是否可行,但您描述了“当BroadcastReceiver成功注册时”,所以我想知道是否存在问题。不成功注册的处理。我还想知道,如果不是
onStart
中的所有分支都注册了广播接收器,是否会发生这种情况

我可以猜测下面的链接可能是相关的,但是您已经使用了一个变量来检查它是否已注册,所以我猜不会:(虽然我不确定我是否喜欢或信任该文本中的措辞,但它使用的示例包括回调)

此外,不能保证组件在活动或片段停止之前启动。这尤其是tr