简体   繁体   English

onStop 在 onDestroy 之后被调用?

[英]onStop being called after onDestroy?

I've encountered a rather strange issue with Activity lifecycle.我在Activity生命周期中遇到了一个相当奇怪的问题。

Short prequel:短前传:

The first symptom that I've found is that it crashed with IllegalArgumentException when I was trying to unregister receiver in onStop after registering it in onStart .我发现的第一个症状是,当我在onStart中注册接收器后尝试在onStop中取消注册接收器时,它与IllegalArgumentException一起崩溃。

After dumping the full list of active receivers (some reflection magic), I've found that my receiver is not the list.在转储活动接收器的完整列表(一些反射魔法)之后,我发现我的接收器不在列表中。 It was either being removed somewhere else by mistake, or it was removed during onDestroy call of Activity where Context is being cleaned (during onDestroy ActivityThread calls ContextImpl#performFinalCleanup , which then calls LoadedApk#removeContextRegistrations ).它要么被错误地移除到其他地方,要么在onDestroy调用Activity期间被移除(在onDestroy ActivityThread调用ContextImpl#performFinalCleanup ,然后调用Context LoadedApk#removeContextRegistrations )。

What is happening?怎么了?

After adding some more analytics info to the crash, I found out that while the crash is happening in onStop , the Activity is in a pretty weird state - it's isDestroyed() call returns true , it's isFinishing() returns false , and it's getLifecycle().getCurrentState() returns DESTROYED ...在向崩溃添加更多分析信息后,我发现当崩溃发生在onStop时, Activity处于一个非常奇怪的 state - isDestroyed()调用返回trueisFinishing()返回false ,它是getLifecycle().getCurrentState()返回DESTROYED ...

Checking normal onStop() (without crash) call shows that the Activity is in this state:检查正常的onStop() (没有崩溃)调用表明Activity位于此 state 中:

isDestroyed() is false , and getLifecycle().getCurrentState() is CREATED in onStop . isDestroyed()falseCREATED getLifecycle().getCurrentState()onStop中创建。

So I drew the conclusion that onStop is being called after onDestroy , which I thought is impossible, but it seems to happen.所以我得出的结论是onStoponDestroy之后被调用,我认为这是不可能的,但它似乎发生了。

And onStop is definitely not being called manually by something else in the app, since this is the stack trace of where the onStop is called from.并且onStop绝对不会被应用程序中的其他东西手动调用,因为这是调用onStop的位置的堆栈跟踪。

com.myapp.TheActivity.onStop (TheActivity.java:217)
android.app.Instrumentation.callActivityOnStop (Instrumentation.java:1474)
android.app.Activity.performStop (Activity.java:8189)
android.app.ActivityThread.callActivityOnStop (ActivityThread.java:4994)
android.app.ActivityThread.performStopActivityInner (ActivityThread.java:4967)
android.app.ActivityThread.handleStopActivity (ActivityThread.java:5047)
android.app.servertransaction.TransactionExecutor.performLifecycleSequence (TransactionExecutor.java:233)
android.app.servertransaction.TransactionExecutor.cycleToPath (TransactionExecutor.java:201)
android.app.servertransaction.TransactionExecutor.executeLifecycleState (TransactionExecutor.java:173)
android.app.servertransaction.TransactionExecutor.execute (TransactionExecutor.java:97)
android.app.ActivityThread$H.handleMessage (ActivityThread.java:2220)
android.os.Handler.dispatchMessage (Handler.java:107)
android.os.Looper.loop (Looper.java:237)
android.app.ActivityThread.main (ActivityThread.java:8016)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:493)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1076)

The reason is unclear, but, it is getting more and more attention recently.原因尚不清楚,但最近越来越受到关注。 And it happens in both onResume/onPause and onStart/onStop pairs to call register/unregister.它发生在 onResume/onPause 和 onStart/onStop 对中调用注册/取消注册。 About those lifeCycle checks, make sure you have on Instance of the activity with hashCode() or something.关于这些生命周期检查,请确保您拥有带有 hashCode() 或其他东西的活动实例。 Anyway, to fix the issue the best practice is to wrap register/unregister calls in try/catch block:无论如何,要解决此问题,最佳做法是将注册/取消注册调用包装在 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
    }
}

I am not entirely sure why that happens in the first place, but I've encountered something similar on one of the Xiaomi devices that did not happen on any of the emulators (or my device), but happened on somebody else's phone.我不完全确定为什么会首先发生这种情况,但是我在其中一个小米设备上遇到了类似的事情,这些事情在任何模拟器(或我的设备)上都没有发生,但发生在别人的手机上。 onStop() was called 5 seconds after the app was moved to background, but onPause() was called immediately.在应用程序移至后台 5 秒后调用onStop() ,但立即调用onPause() More weird issue, if in between these 5 seconds, I open the app from task manager, onStart() was called.更奇怪的问题,如果在这 5 秒之间,我从任务管理器打开应用程序,就会onStart() (Notice the 2 onStart() calls but not a singular onStop() call.) I think it would have been possible if the activity was destroyed, onDestroy() would be called before onStop() . (注意 2 个onStart()调用,但不是单个onStop()调用。)我认为如果活动被销毁, onDestroy()将在onStop()之前调用。 As an alternative, you might try to move the receiver registration calls to onResume() and onPause() instead of onStart() and onStop() .作为替代方案,您可以尝试将接收者注册调用移动到onResume()onPause()而不是onStart()onStop()

Second: I don't exactly use lifecycle of the activity when it comes to checking resumed or paused state, but I'd suggest overriding all of those methods (onPause, onResume etc...), storing the state on boolean variables and logging the state while checking the actual calls.第二:在检查恢复或暂停 state 时,我不完全使用活动的生命周期,但我建议覆盖所有这些方法(onPause、onResume 等),将 state 存储在 Z824E2EAC64F38A2DA78 变量上state 同时检查实际呼叫。 Maybe that will result in a different state since this is a pretty unusual check.也许这会导致不同的 state 因为这是一个非常不寻常的检查。

If it does not happen on other activities, in that activity, maybe something is posting so many callbacks to the main message looper that prevents onStop() from getting called in the first place because of the overflow, causing this exception to happen.如果它没有发生在其他活动上,那么在该活动中,可能有一些东西正在向主消息循环器发布如此多的回调,从而阻止onStop()由于溢出而首先被调用,从而导致发生此异常。 These are only assumptions, of course, but I'd be grateful if they helped in a way.当然,这些只是假设,但如果它们在某种程度上有所帮助,我将不胜感激。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM