最近发现项目里的一个问题.从 Activity A 进入 Activity B.然后从B返回的时候理论上应该是A onResume之后就会走B的onStop,onDestroy.但是并不是,发现在极端情况下会延迟将近10s.导致有些资源没有释放(项目中是音视频资源没有释放,导致还在播放语音)带着疑问我就去研究了finish的源代码
public void finish() {
finish(DONT_FINISH_TASK_WITH_ACTIVITY);
}
复制
注意这个 DONT_FINISH_TASK_WITH_ACTIVITY 参数.这个函数最终会调用 ActivityManagerService.finishActivity
public final boolean finishActivity(IBinder token, int resultCode, Intent resultData,
int finishTask) {
......
try {
boolean res;
final boolean finishWithRootActivity =
finishTask == Activity.FINISH_TASK_WITH_ROOT_ACTIVITY;
if (finishTask == Activity.FINISH_TASK_WITH_ACTIVITY
|| (finishWithRootActivity && r == rootR)) {//走 else 分支
......
} else {
res = tr.getStack().requestFinishActivityLocked(token, resultCode,
resultData, "app-request", true);
}
return res;
} finally {
}
}
}
复制
finishTask = DONT_FINISH_TASK_WITH_ACTIVITY,所以走 requestFinishActivityLocked, finishActivityLocked.
这里要先注意一下 pauseImmediately 的 boolean 值.从 finishActivityLocked 来看,应该是 false
final boolean finishActivityLocked(ActivityRecord r, int resultCode, Intent resultData,
String reason, boolean oomAdj, boolean pauseImmediately) {
......
try {
// 设置r.finishing=true; 标记当前Activity为finishing
r.makeFinishingLocked();
......
if (mResumedActivity == r) {// 当前Activity即为活动Activity,进入if分支
......
r.setVisibility(false);
// 还未暂停当前Activity,因此mPausingActivity为null
if (mPausingActivity == null) {
// 开始暂停当前Activity
startPausingLocked(false, false, null, pauseImmediately);
}
} else if (r.state != ActivityState.PAUSING) {
// PAUSING结束,直接finish
......
} else {
// 正在 PAUSING,等它结束
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish waiting for pause of: " + r);
}
return false;
} finally {
}
}
复制
接下来看 startPausingLocked
final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping,
ActivityRecord resuming, boolean pauseImmediately) {
......
ActivityRecord prev = mResumedActivity;
......
mResumedActivity = null;
mPausingActivity = prev;
......
// 设置当前Activity的状态为pausing
prev.state = ActivityState.PAUSING;
......
if (prev.app != null && prev.app.thread != null) {
try {
// 在 ActivityThread 里面
// 先走到 performPauseActivity.这里面会有onPause的调用
// 然后调用 AMS 的 activityPaused
prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
userLeaving, prev.configChangeFlags, pauseImmediately);
} catch (Exception e) {
......
}
} else {
......
}
......
if (mPausingActivity != null) {// 前面已经赋值
......
if (pauseImmediately) {// 前面已经提到,是 false
completePauseLocked(false, resuming);
return false;
} else {
// 向AMS主线程发送一个延时500ms的消息,执行completePauseLocked
schedulePauseTimeout(prev);
return true;
}
} else {
......
}
}
复制
这里一共有两个分支
- prev.app.thread.schedulePauseActivity
- schedulePauseTimeout(相对简单,注释里已经有了)
schedulePauseActivity最终会走到AMS 的 activityPaused
final void activityPausedLocked(IBinder token, boolean timeout) {
final ActivityRecord r = isInStackLocked(token);
if (r != null) {
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
if (mPausingActivity == r) {
......
try {
// 开始执行当前 Activity 暂停后的流程
// 参数 resumeNext 为 true,表示需要唤起下一个 Activity
completePauseLocked(true /* resumeNext */, null /* resumingActivity */);
} finally {
mService.mWindowManager.continueSurfaceLayout();
}
return;
} else {
......
}
}
}
复制
由此可见 startPausingLocked 最终都会走到 completePauseLocked
看一下 completePauseLocked
private void completePauseLocked(boolean resumeNext, ActivityRecord resuming) {
ActivityRecord prev = mPausingActivity;
if (prev != null) {
final boolean wasStopping = prev.state == STOPPING;
prev.state = ActivityState.PAUSED;
if (prev.finishing) {// 之前已经是 true
prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false);
} else if (prev.app != null) {
......
} else {
......
}
......
mPausingActivity = null;
}
if (resumeNext) {// 传进来是 true
final ActivityStack topStack = mStackSupervisor.getFocusedStack();
if (!topStack.shouldSleepOrShutDownActivities()) {
// 代码很多,主要还是调用下一个 Activity 的 onResume 方法
mStackSupervisor.resumeFocusedStackTopActivityLocked(topStack, prev, null);
} else {
......
}
}
......
}
复制
主要是以下两个函数
- finishCurrentActivityLocked
- resumeFocusedStackTopActivityLocked
看一下第一个 finishCurrentActivityLocked.注意传入的参数
final ActivityRecord finishCurrentActivityLocked(ActivityRecord r, int mode, boolean oomAdj) {
......
final ActivityRecord next = mStackSupervisor.topRunningActivityLocked();
if (mode == FINISH_AFTER_VISIBLE && (r.visible || r.nowVisible)
&& next != null && !next.nowVisible) {
if (!mStackSupervisor.mStoppingActivities.contains(r)) {
addToStopping(r, false /* scheduleIdle */, false /* idleDelayed */);
}
r.state = STOPPING;
return r;
}
......
}
复制
看一下 addToStopping.注意传入的参数
void addToStopping(ActivityRecord r, boolean scheduleIdle, boolean idleDelayed) {
if (!mStackSupervisor.mStoppingActivities.contains(r)) {
mStackSupervisor.mStoppingActivities.add(r);
}
boolean forceIdle = mStackSupervisor.mStoppingActivities.size() > MAX_STOPPING_TO_FORCE
|| (r.frontOfTask && mTaskHistory.size() <= 1);
// scheduleIdle = false, forceIdle = true
if (scheduleIdle || forceIdle) {
// idleDelayed = false
if (!idleDelayed) {
mStackSupervisor.scheduleIdleLocked();
} else {
// 延迟发送10s IDLE信号
mStackSupervisor.scheduleIdleTimeoutLocked(r);
}
} else {
checkReadyForSleep();
}
}
复制
由此可见 finishCurrentActivityLocked 就是延迟10s执行 activityIdleInternalLocked
接下来看第二个函数 resumeFocusedStackTopActivityLocked
boolean resumeFocusedStackTopActivityLocked() {
return resumeFocusedStackTopActivityLocked(null, null, null);
}
boolean resumeFocusedStackTopActivityLocked(
ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
if (!readyToResume()) {
return false;
}
if (targetStack != null && isFocusedStack(targetStack)) {
return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
if (r == null || r.state != RESUMED) {// 肯定走这里
mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
} else if (r.state == RESUMED) {
// Kick off any lingering app transitions form the MoveTaskToFront operation.
mFocusedStack.executeAppTransition(targetOptions);
}
return false;
}
复制
然后走 resumeTopActivityInnerLocked.里面最重要的就是
try {
......
next.sleeping = false;
mService.showUnsupportedZoomDialogIfNeededLocked(next);
mService.showAskCompatModeDialogLocked(next);
next.app.pendingUiClean = true;
next.app.forceProcessStateUpTo(mService.mTopProcessState);
next.clearOptionsLocked();
next.app.thread.scheduleResumeActivity(next.appToken, next.app.repProcState,
mService.isNextTransitionForward(), resumeAnimOptions);
} catch (Exception e) {
......
}
复制
最终走这里
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
ActivityClientRecord r = mActivities.get(token);
......
unscheduleGcIdler();//mGcIdlerScheduled=false,后面要用到
mSomeActivitiesChanged = true;
// 即将要 resume 的 activity 的参数调整
r = performResumeActivity(token, clearHide, reason);
if (r != null) {//一般不为 null
final Activity a = r.activity;
...... 让整个 Activity 可见,并且调整 layout 布局
if (!r.onlyLocalRequest) {
r.nextIdle = mNewActivities;
mNewActivities = r;
// 看看 Idler 是啥
// 往主线程的消息队列添加了一个空闲处理器,当主线程空闲时就会回调这个处理器来执行一些优先级较低的任务
Looper.myQueue().addIdleHandler(new Idler());
}
r.onlyLocalRequest = false;
if (reallyResume) {
try {
//正式onResume
ActivityManager.getService().activityResumed(token);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
} else {
......
}
}
复制
Idler 里面会调用 ActivityManager.getService.activityIdle 方法.最终调用 activityIdleInternalLocked
final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout,
boolean processPausingActivities, Configuration config) {
......
// Stop any activities that are scheduled to do so but have been
// waiting for the next one to start.
for (int i = 0; i < NS; i++) {
r = stops.get(i);
final ActivityStack stack = r.getStack();
if (stack != null) {
if (r.finishing) {
//注意参数 FINISH_IMMEDIATELY
//注意是 stops 数组,调用onStop
stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY, false);
} else {
stack.stopActivityLocked(r);
}
}
}
for (int i = 0; i < NF; i++) {
r = finishes.get(i);
final ActivityStack stack = r.getStack();
if (stack != null) {
//finishes 数组,调用onDestroy
activityRemoved |= stack.destroyActivityLocked(r, true, "finish-idle");
}
}
......
return r;
}
复制
finish的流程基本总结如下
- (1)标记当前 Activity 为 finishing
- (2)设置当前 Activity 的状态为 pausing (这里正式开始pause)
- (3)调用当前 Activity 的 onPause 回调
- (4)completePauseLocked(不管是直接执行还是延迟500ms执行)(开始执行当前 Activity 暂停后的流程)
- (5)对即将 resume 的 Activity 进行 layout 调整,然后添加一个空闲处理器,最后正式 onResume
- 另外,延迟10s发送 IDLE 信号到处理器去强制 onStop,onDestroy
接下来就有个疑问了,为啥 onStop,onDestroy 没有立即执行?原因就在这个空闲处理器
addIdleHandler 是在 MessageQueue 里面的,也就是说的消息队列.只有一个地方调用了 Idler.queueIdle
Message next() {
......
for (;;) {
......
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
......
}
for (int i = 0; i < pendingIdleHandlerCount; i++) {
......
try {
keep = idler.queueIdle();//************************
} catch (Throwable t) {
}
......
}
......
}
}
复制
看到它调用的地方了没?必须要等到 MessageQueue 里面没有数据的时候才会去调用
也就是说 onStop,onDestroy 的调用和消息队列有关.如果消息队列很快就空了, onStop,onDestroy 就很快返回.如果主线程还有消息未处理(比如一直 invalidate )会一直处理,直到超过10s强制调用
现在终于明白为啥 onStop,onDestroy 没有直接返回.那么文章最初的问题又该如何处理呢?很简单,在onPause里面用isFinishing方法来判断,如果是true,就去取消音视频,让用户无感知(并没有真正解决问题,如果要真正解决问题还是需要从主线程消息队列来考虑)