问题
- 步骤:在计算器面板上出入数字,然后按Menu键进入最近任务界面,右滑清楚计算器,接着再进入计算器
- 期望结果:再次进入计算器,上面显示的内容和之前的一致
- 实际结果:没有保存
初步分析
开发计算器的工程师A说保存的代码写在了onDestory内,他说因为计算器的生命周期没有走完酒杯杀掉了,觉得是系统的问题,让系统的工程师看
我看了问题和工程师A的回复,我首先说,保存重要数据,不要保存在onStop和onDestory内,Android开发者文档中也有说明
至于为什么onDestory没有走完,我怀疑是并行的原因,需要在代码里去找证据
具体分析
-
removeTaskByIdLocked
文件:AMS
private boolean removeTaskByIdLocked(int taskId, boolean killProcess,
boolean removeFromRecents) {
......
if (tr != null) {
tr.removeTaskActivitiesLocked(); //清除Task中的activity,见 2
cleanUpRemovedTaskLocked(tr, killProcess, removeFromRecents); //清除相关的进程,见3
......
}
return false;
}在最近任务界面右滑时,会调用上面这个方法,里面有两个很重要的方法,分别是removeTaskActivitiesLocked和cleanUpRemovedTaskLocked,我们先来看看removeTaskActivitiesLocked
-
removeTaskActivitiesLocked
文件:TaskRecord.java
public void removeTaskActivitiesLocked() {
// 见2.1
performClearTaskAtIndexLocked(0);
}2.1 performClearTaskAtIndexLocked
文件:TaskRecord.java
final void performClearTaskAtIndexLocked(int activityNdx) {
int numActivities = mActivities.size();
for ( ; activityNdx < numActivities; ++activityNdx) {
......
else if (stack.finishActivityLocked(
r, Activity.RESULT_CANCELED, null, "clear-task-index", false)) {
);
--activityNdx;
--numActivities;
}
}
}上面会调用finishActivityLocked,我们继续往下看
2.2 finishActivityLocked
文件:ActivityStack.java
final boolean finishActivityLocked(ActivityRecord r, int resultCode, Intent resultData,
String reason, boolean oomAdj) {
......
else if (r.state != ActivityState.PAUSING) {
......
// 见2.3
return finishCurrentActivityLocked(r, (r.visible || r.nowVisible) ?
FINISH_AFTER_VISIBLE : FINISH_AFTER_PAUSE, oomAdj) == null;
}
......
}
2.3 finishCurrentActivityLocked
文件:ActivityStack.java
final ActivityRecord finishCurrentActivityLocked(ActivityRecord r, int mode, boolean oomAdj)
{
......
if (mode == FINISH_IMMEDIATELY
|| (prevState == ActivityState.PAUSED
&& (mode == FINISH_AFTER_PAUSE || mode == FINISH_AFTER_VISIBLE
|| mStackId == PINNED_STACK_ID))
|| prevState == ActivityState.STOPPED
|| prevState == ActivityState.INITIALIZING) {
r.makeFinishingLocked();
// 见2.4
boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm");
......
}
2.4 destroyActivityLocked
文件:ActivityStack.java
final boolean destroyActivityLocked(ActivityRecord r, boolean removeFromApp, String reason) {
......
try {
// 见2.5
r.app.thread.scheduleDestroyActivity(r.appToken, r.finishing,
r.configChangeFlags);
}
......
}马上要开始进行Binder调用了,System Sever这边是客户端,所以接下来是着ApplicationThreadProxy.java中的scheduleDestroyActivity
2.5 scheduleDestroyActivity
public final void scheduleDestroyActivity(IBinder token, boolean finishing,
int configChanges) throws RemoteException {
......
mRemote.transact(SCHEDULE_FINISH_ACTIVITY_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
......
}注意上面的IBinder.FLAG_ONEWAY参数,这说明该binder调用是非阻塞的,这样问题可以解释的通了,接下来系统进程这边的代码会继续跑,不会等App进程那边的反馈,就当App进程那边准备处理这个SCHEDULE_FINISH_ACTIVITY_TRANSACTION消息时,App已经被杀掉了,所以计算器写在onDestory内的代码也就没有机会执行了
-
cleanUpRemovedTaskLocked
文件:AMS
private void cleanUpRemovedTaskLocked(TaskRecord tr, boolean killProcess,
boolean removeFromRecents) {
......
// Kill the running processes.
for (int i = 0; i < procsToKill.size(); i++) {
ProcessRecord pr = procsToKill.get(i);
if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND
&& pr.curReceiver == null) {
pr.kill("remove task", true);
} else {
// We delay killing processes that are not in the background or running a receiver.
pr.waitingToKill = "remove task";
}
}
}这就是杀进程的方法
-
时序图
上面的方法中,除了ATN,ApplicationThread,ActivityThread是跑在App进程,其他都跑在System Sever进程
-
总结
其实前面都已经说了,这里再罗嗦一下,不要在onStop,onDestory中保存重要数据;最近任务栏清除app,app的onDestory不会掉用是因为该Binder调用是非阻塞的,导致App被杀死,所以onDestory没来得及调用