Android Activity状态保存(onSaveInstanceState)

Activity状态保存

某些情况下,Activity会被杀死然后重新创建,比如系统设定表示Size变化,Font Size变化,横竖屏切换等。如果Activity在AndroidManifest中配置了android:configChanges属性,则在对应的Config发生变化时不会销毁Activity再重新创建,而是会执行onConfigurationChanged,这时Activity没有被销毁重建也就不需要进行状态的保存。所以通过配置android:configChanges可以规避某些需要保存数据的情形。

配置过android:configChanges=“orientation”,当翻转屏幕时会自动地加载相应的布局文件吗?其实不会哦,也就是开始时是加载水平布局切换到垂直状态也还是水平布局(只指R.id.content对应的部分),因为onCreate没有重新执行,另外自动地加载对应文件夹的资源文件需要使用Resources.getXXX方法,而setContentView是在onCreate里调用的,当onCreate没有调用时自然就不会自动加载相应的布局。

onConfigurationChanged调用时机:Android H之前在onPause前调用,P之前在onStop前调用,P之后在onStop后。

恢复数据一般在onCreate里判断savedInstanceState不等于null,即为需要恢复数据的场合。

强制杀死进程不能自动恢复数据,即savedInstanceState等于null。比如通过AndroidStudio杀死,adb shell am force-stop。

测试时发现adb shell am kill可以自动地恢复数据,看此命令的解释信息为:Kill all background processes associated with the given application.

下面来分析force-stop和kill的不同:
行为上,force-stop不管包是前台还是后台都会杀死进程,通过task一览不能恢复原来的栈,只能打开原来栈低的Activity。kill则只能杀死后台包,通过task一览可以恢复原来的栈。设定中App详细信息里的force stop对应的就是force-stop(行为一致,没有看源码)。

ActivityManagerShellCommand.java
                case "force-stop":
                    return runForceStop(pw);
                case "kill":
                    return runKill(pw);
                    
	int runKill(PrintWriter pw) throws RemoteException {
        int userId = UserHandle.USER_ALL;

        String opt;
        while ((opt=getNextOption()) != null) {
            if (opt.equals("--user")) {
                userId = UserHandle.parseUserArg(getNextArgRequired());
            } else {
                getErrPrintWriter().println("Error: Unknown option: " + opt);
                return -1;
            }
        }
        mInterface.killBackgroundProcesses(getNextArgRequired(), userId);
        return 0;
    }
    
    int runForceStop(PrintWriter pw) throws RemoteException {
        int userId = UserHandle.USER_ALL;

        String opt;
        while ((opt = getNextOption()) != null) {
            if (opt.equals("--user")) {
                userId = UserHandle.parseUserArg(getNextArgRequired());
            } else {
                getErrPrintWriter().println("Error: Unknown option: " + opt);
                return -1;
            }
        }
        mInterface.forceStopPackage(getNextArgRequired(), userId);
        return 0;
    }

很显然对应了ActivityManagerService的两个不同方法,forceStopPackage和killBackgroundProcesses。

代码过多此处省略一部分:

 public void killBackgroundProcesses(final String packageName, int userId) {
      		...
                synchronized (this) {
                    mProcessList.killPackageProcessesLocked(packageName, appId, targetUserId,
                            ProcessList.SERVICE_ADJ, "kill background");
                }
			...
    }
        @Override
    public void forceStopPackage(final String packageName, int userId) {
        		...
                    try {
                        pm.setPackageStoppedState(packageName, true, user);
                    } catch (RemoteException e) {
                    } catch (IllegalArgumentException e) {
                        Slog.w(TAG, "Failed trying to unstop package "
                                + packageName + ": " + e);
                    }
                    if (mUserController.isUserRunning(user, 0)) {
                        forceStopPackageLocked(packageName, pkgUid, "from pid " + callingPid);
                        finishForceStopPackageLocked(packageName, pkgUid);
                    }
                    ...
    }
    private void forceStopPackageLocked(final String packageName, int uid, String reason) {
        forceStopPackageLocked(packageName, UserHandle.getAppId(uid), false,
                false, true, false, false, UserHandle.getUserId(uid), reason);
    }
    @GuardedBy("this")
    final boolean forceStopPackageLocked(String packageName, int appId,
            boolean callerWillRestart, boolean purgeCache, boolean doit,
            boolean evenPersistent, boolean uninstalling, int userId, String reason) {
...
//最终通过 Process.killProcessQuiet(pid); ProcessList.killProcessGroup(uid, pid);杀死进程,
//但不对栈进行操作
        boolean didSomething = mProcessList.killPackageProcessesLocked(packageName, appId, userId,
                ProcessList.INVALID_ADJ, callerWillRestart, true /* allowRestart */, doit,
                evenPersistent, true /* setRemoved */,
                packageName == null ? ("stop user " + userId) : ("stop " + packageName));
//这里是关键,通过调试发现会对栈中每个Activity进行finish的操作,所以栈被破坏,
//再次启动只会启动第一个Activity
        didSomething |=
                mAtmInternal.onForceStopPackage(packageName, doit, evenPersistent, userId);
    }

综上所述,kill只是杀死进程,不对栈进行操作,而force-stop多了一个遍历栈内Activity并执行finish的操作,所以栈被破坏了。

因内存不足而被杀死的进程可以自动恢复吗?经测试是可以的。看代码也印证了这一点:
当updateOomAdjLocked时,如果发现缓存进程或者缓存空进程超过了限制数量就会执行ProcessRecord.kill方法,但不对栈进行操作,所以可以恢复数据。

什么是空进程(PROCESS_STATE_CACHED_EMPTY)?

OomAdjuster.java
    private final boolean computeOomAdjLocked(ProcessRecord app, int cachedAdj,
            ProcessRecord TOP_APP, boolean doingAll, long now, boolean cycleReEval) {
        //thread为IApplicationThread,IApplicationThread是应用进程同AMS交互的aidl对象。
        //可以推断app.thread == null意味着,AMS和应用进程解除绑定。
        if (app.thread == null) {
            app.adjSeq = mAdjSeq;
            app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_BACKGROUND);
            app.setCurProcState(PROCESS_STATE_CACHED_EMPTY);
            app.curAdj = ProcessList.CACHED_APP_MAX_ADJ;
            app.setCurRawAdj(ProcessList.CACHED_APP_MAX_ADJ);
            app.completedAdjSeq = app.adjSeq;
            return false;
        }
ProcessRecord.java
public void makeInactive(ProcessStatsService tracker) {
        thread = null;
}

所以在makeInactive被执行时,进程变成空进程,此时同AMS的连接被解除。
下面是进程被杀死的情境的调用栈。
makeInactive:661, ProcessRecord (com.android.server.am)
cleanUpApplicationRecordLocked:13783, ActivityManagerService (com.android.server.am)
handleAppDiedLocked:3661, ActivityManagerService (com.android.server.am)
appDiedLocked:3819, ActivityManagerService (com.android.server.am)
binderDied:1522, ActivityManagerService$AppDeathRecipient (com.android.server.am)
sendDeathNotice:620, BinderProxy (android.os)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值