先看一张按下 Back 键之后,Activity 生命周期回调的日志截图:

从日志中可以看到当按下 Back 键时,当前的 Activity 会马上回调 onPause() 方法,而 onStop() 是在 MainActivity 的 onResume()之后才调用,onPause() 与 onStop()之间相隔了大约 300ms,也就是说 Activity 不是马上被销毁的。
再看另一个快速重新打开 LifeActivity
的 Case:

这里我采用代码模拟快速重新打开 LifeActivity
,finish() 后延迟 300ms 再启动 LifeActivity
。因为我们的 Activity 里没做什么事,所以很难手动重现快速重新打开 Activity 的异常 Case,而实际项目因为逻辑复杂,往往在1~2s或者更长的时间里很容易复现这种情况。
出现了诡异的事:LifeActivity[33732136] 是旧的 Activity,但它却在新的 LifeActivity[212157058] 显示之后才被销毁的,看到这个可能你已经心头一凉。这会导致什么问题呢?这会让我们依赖 Activity 生命周期回调来做资源回收的代码变得不可靠。
举个栗子:如果我们在 onStart() 中启动相机在 onStop() 中关闭相机,正常重新打开这个页面时相机的状态操作:打开 -> 关闭 -> 打开,快速重新打开这个 Activity 时就可能不是这个顺序了:打开->打开->关闭。然后用户就遭殃了,他将无法正常使用你的应用了,而用户只是因为手速过快。
分析
那么为什么 onPause() 是马上被调用,而 onStop() 和 onDestroy() 却被延迟这么久呢?
关于 Activity 销毁流程的源码我不会做详细分析,具体可以查看相关源码或者搜索其他人的文章看下
调用 finish 方法后会经过以下流程向 ActivityManagerService
请求销毁当前 Activity:
1 2 3 4 5 6 7
| MyActivity.finish() Activity.finish() ActivityManagerNative.getDefault().finishActivity() ActivityManagerService.finishActivity() ActivityStack.requestFinishActivityLocked() ActivityStack.finishActivityLocked() ActivityStack.startPausingLocked()
|
然后 ActivityManagerService
就会请求执行当前 Activity 的 onPause() 方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| IApplicationThread.schedulePauseActivity() ActivityThread.schedulePauseActivity() ActivityThread.sendMessage() ActivityThread.H.sendMessage() ActivityThread.H.handleMessage() ActivityThread.handlePauseActivity() ActivityThread.performPauseActivity() Instrumentation.callActivityOnPause() Activity.performPause() Activity.onPause() ActivityManagerNative.getDefault().activityPaused() ActivityManagerService.activityPaused() ActivityStack.activityPausedLocked() ActivityStack.completePauseLocked()
|
所以 onPause() 是立即被执行的,执行完 onPause() 后并没有马上销毁 Activity,而是先让一个 Activity 显示出来,这个 Activity 可能是当前应用 Activity 栈中的一个 Activity 也可能是 Launcher 或者其他应用的 Activity,不管是哪个都大同小异,在上面的 Case 中就是 MainActivity。
执行上一个 Activity 即 MainActivity 的 onResume()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| ActivityStack.resumeTopActivityLocked() ActivityStack.resumeTopInnerLocked() IApplicationThread.scheduleResumeActivity() ActivityThread.scheduleResumeActivity() ActivityThread.sendMessage() ActivityTherad.H.sendMessage() ActivityThread.H.handleMessage() ActivityThread.handleResumeActivity() Activity.performResume() Activity.performRestart() Instrumentation.callActivityOnRestart() Activity.onRestart() Activity.performStart() Instrumentation.callActivityOnStart() Activity.onStart() Instrumentation.callActivityOnResume() Activity.onResume()
|
执行完上一个 Activity 的 onResume 之后,该进行 Activity 的销毁操作了吧?
通过反向分析,发现 Activity 的销毁时通过请求 ActivityManagerService 的 activityIdle() 方法,销毁流程如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| Looper.myQueue().addIdleHandler(new Idler()) ActivityManagerNative.getDefault().activityIdle() ActivityManagerService.activityIdle() ActivityStackSupervisor.activityIdleInternalLocked() ActivityStack.destroyActivityLocked() IApplicationThread.scheduleDestoryActivity() ActivityThread.scheduleDestoryActivity() ActivityThread.sendMessage() ActivityThread.H.sendMessage() ActivityThread.H.handleMessage() ActivityThread.handleDestoryActivity() ActivityThread.performDestoryActivity() Activity.performStop() Instrumentation.callActivityOnStop() Activity.onStop() Instrumentation.callActivityOnDestory() Activity.performDestory() Acitivity.onDestory() ActivityManagerNative.getDefault().activityDestoryed() ActivityManagerService.activityDestoryed() ActivityStack.activityDestoryedLocked()
|
这个 Idler 实现的是 MessageQueue.IdleHandler
,IdleHandler 会等到 MessageQueue 中当前没有可执行的消息时才会执行,也就是说 Activity 会一直等待主线程消息队列中当前消息都处理完毕了才会进行销毁,这也就是 Activity 的销毁不是立即执行的根本原因。
如何避免
手速快并不是用户的锅,要避免这种情况,可以用个静态变量保存当前 Activity,并且在销毁的时候判断下是不是与保存的一致,以下给出示例代码,如果你有更好的方案,欢迎告诉我 :)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| public class LifeActivity extends AppCompatActivity {
private static LifeActivity sCurrentLifeActivity;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); sCurrentLifeActivity = this; } @Override protected void onStart() { super.onStart(); someResource.open(); }
@Override protected void onStop() { super.onStop(); if (sCurrentLifeActivity == this) { someResource.close(); } }
@Override protected void onDestroy() { super.onDestroy(); if (sCurrentLifeActivity == this) { sCurrentLifeActivity = null; } }
}
|