web-dev-qa-db-ja.com

アクティビティコンテキストに登録されているBroadcastReceiverの登録を解除すると、IllegalArgumentExceptionがクラッシュする

クラッシュはかなり奇妙なものです。

onStartには、Activityフィールドに格納されているBroadcastReceiverが登録されています。 onStopでは、このBroadcastReceiverは登録されていません。 BroadcastReceiverが正常に登録されたら、isRegisteredフィールドもtrueに設定し、レシーバーの登録を解除する前に、このフィールドをチェックして、必要かどうかを確認します

ただし、Crashlyticsではこれが失敗することがあり、Receiver not registeredから発生するAndroid.app.LoadedApk#forgetReceiverDispatcherメッセージとともにIllegalArgumentExceptionでアプリ全体がクラッシュすることがわかりました。私がフラグをチェックすることを考えると、どれがかなり奇妙なことでしょう?

登録/登録解除を処理するContextImplおよびLoadedApkクラスを調べて、リフレクションに基づく診断を追加した後、さらに不思議になりました。つまり、このようなクラッシュが発生するたびに、既存のContextからBroadcastReceiverへのマップを抽出します( ContextImpl.Java:159 および LoadedApk.Javaを参照)。 :1361 )。

登録が正常に解除されると、クラッシュせずに次のようなマップが表示されます。

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

つまり、BroadcastReceiverを呼び出したことはありませんが、私のunregisterReceiverが登録されているアクティビティはありません。

それは1つの特定のアクティビティでのみ発生するので、最初の推測では、このアクティビティは何らかの形でリークされ、onDestroyライフサイクルが呼び出され、アクティビティエントリがレシーバーマップから削除されます。登録を解除してください。ただし、その場合、onStopの後にonDestroyが呼び出されるのはなぜですか?そして、なぜレシーバーリストは完全に空ですか?

そして、それがリークでない場合、何がそのような不可解な行動につながる可能性がありますか?他の誰かがこのような奇妙な出来事を経験し、私を助けることができることを心から願っています。

1

私はこの方法で実装を行いました:

OnDestroyイベントでレシーバーを解放する

@Override
public void onDestroy() {

    // ...releasing more objects

    LocalBroadcastManager.getInstance(this).unregisterReceiver(testReceiver);
    super.onDestroy();
}
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // ... more initializations

    initializeBroadcastReceivers();
}


private void initializeBroadcastReceivers()
{
    LocalBroadcastManager.getInstance(this)
      .registerReceiver(testReceiver, 
        new IntentFilter("testReceiver"));
}

private BroadcastReceiver testReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        // some code
    }
};
0
Ariel Perez