您的位置:首页 > 移动开发 > Android开发

Android之什么时候调用onSaveInstance方法的时候(为什么按Home键盘会调用,按Back不调用)

2017-04-18 00:51 627 查看

1、函数介绍

1)、onCreate(Bundle savedInstanceState) 方法

Activity 创建时回调 : 该方法会自动传入一个 Bundle 对象, 该 Bundle 对象就是上次被系统销毁时在 onSaveInstanceState 或者 onRestoreInstanceState 中保存的数据

-- 注意 : 只有是系统自动回收的时候才会保存 Bundle 对象数据;

-- Bundle 对象来源 : onCreate() 方法中的 Bundle 对象参数, 是在 onSaveInstance() 或者 onRestoreInstanceState() 方法中保存的 Bundle 对象;

2)、 onSaveInstanceState(Bundle outState) 方法

onSaveInstanceState函数是Activity的生命周期函数

outState 参数作用 :

 数据保存 : Activity 声明周期结束的时候, 需要保存 Activity 状态的时候, 会将要保存的数据使用键值对的形式 保存在 Bundle 对象中;

 恢复数据 : 在 Activity 的 onCreate()方法 创建 Activity 的时候会传入一个 Bundle 对象, 这个 Bundle 对象就是这个 outState 参数;

调用时机 : Activity 容易被销毁的时候调用, 注意是容易被销毁, 也可能没有销毁就调用了;
按下Home键 : Activity 进入了后台, 此时会调用该方法;

按下电源键 : 屏幕关闭, Activity 进入后台;

启动其它 Activity : Activity 被压入了任务栈的栈底;

横竖屏切换 : 会销毁当前 Activity 并重新创建;

onSaveInstanceState方法调用注意事项 :

 用户主动销毁不会调用 : 当用户点击回退键 或者 调用了 finish() 方法, 不会调用该方法;

调用时机不固定 : 该方法一定是在 onStop() 方法之前调用, 但是不确定是在 onPause() 方法之前 还是 之后调用;

布局中组件状态存储 : 每个组件都 实现了 onSaveInstance() 方法, 在调用函数的时候, 会自动保存组件的状态, 注意, 只有有 id 的组件才会保存;

关于默认的 super.onSaveInstanceState(outState) : 该默认的方法是实现 组件状态保存的;

(3) onRestoreInstanceState(Bundle savedInstanceState) 方法

方法回调时机 : 在 Activity 被系统销毁之后 恢复 Activity 时被调用, 只有销毁了之后重建的时候才调用, 如果内存充足, 系统没有销毁这个 Activity, 就不需要调用;

-- Bundle 对象传递 : 该方法保存的 Bundle 对象在 Activity 恢复的时候也会通过参数传递到 onCreate() 方法中;

2、源码分析调用onSaveInstance函数的时候

1)、看下ActivityThread.handlePauseActivity的源码
private void handlePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges, boolean dontReport) {
ActivityClientRecord r = mActivities.get(token);
if (r != null) {
//Slog.v(TAG, "userLeaving=" + userLeaving + " handling pause of " + r);
if (userLeaving) {
performUserLeavingActivity(r);
}

r.activity.mConfigChangeFlags |= configChanges;
performPauseActivity(token, finished, r.isPreHoneycomb());

// Make sure any pending writes are now committed.
if (r.isPreHoneycomb()) {
QueuedWork.waitToFinish();
}

// Tell the activity manager we have paused.
if (!dontReport) {
try {
ActivityManagerNative.getDefault().activityPaused(token);
} catch (RemoteException ex) {
}
}
mSomeActivitiesChanged = true;
}
}


再看performPauseActivity方法
final Bundle performPauseActivity(IBinder token, boolean finished,
boolean saveState) {
ActivityClientRecord r = mActivities.get(token);
return r != null ? performPauseActivity(r, finished, saveState) : null;
}


再看掉用重载方法performPauseActivity

final Bundle performPauseActivity(ActivityClientRecord r, boolean finished,
boolean saveState) {
...
if (!r.activity.mFinished && saveState) {
callCallActivityOnSaveInstanceState(r);
}
...
}
我们知道调用callCallActivityOnSaveInstanceState方法,看名称发现这里应该回调的是Activity的onSaveInstanceState方法,我们再看掉用这个函数的条件
!r.activity.mFinished && saveState
如果activity没有掉用finish()
方法,mFinished的值就是false,如果需要进入这个函数,就需要后面的值saveState值为0,这里的saveState是performPauseActivity方法传递过来的
performPauseActivity(token, finished, r.isPreHoneycomb());
我们再看函数r.isPreHoneycomb
public boolean isPreHoneycomb() {
if (activity != null) {
return activity.getApplicationInfo().targetSdkVersion
< android.os.Build.VERSION_CODES.HONEYCOMB;
}
return false;
}
App设置的targetSdk版本号小于android
versionCode 11也就是android3.0的时候返回为true,其他的时候返回为false,也就是说当我们App设置的targetVersion大于android3.0的时候才会执行callCallActivityOnSaveInstanceState方法,然后接着看callCallActivityOnSaveInstanceState方法,如下
private void callCallActivityOnSaveInstanceState(ActivityClientRecord r) {
r.state = new Bundle();
r.state.setAllowFds(false);
if (r.isPersistable()) {
r.persistentState = new PersistableBundle();
mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state,
r.persistentState);
} else {
mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state);
}
}
我们再去Instrumentation.java里面去看函数callActivityOnSaveInstanceState
public void callActivityOnSaveInstanceState(Activity activity, Bundle outState,
PersistableBundle outPersistentState) {
activity.performSaveInstanceState(outState, outPersistentState);
}
我们再去Activity.java里面去看函数performSaveInstanceState实现
final void performSaveInstanceState(Bundle outState) {
onSaveInstanceState(outState);
saveManagedDialogs(outState);
mActivityTransitionState.saveState(outState);
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onSaveInstanceState " + this + ": " + outState);
}
可以看到这里掉用了Activity的onSaveInstanceState方法,这样经过一系列的方法回调之后就执行了onSaveInstanceState方法。

接下来我们看下onStop方法是否会执行onSaveInstanceState方法,同理Actvitiy执行onStop方法会回调ActivityThread的handleStopActivity

接下来我们看handleStopActivity方法的实现:

private void handleStopActivity(IBinder token, boolean show, int configChanges) {
ActivityClientRecord r = mActivities.get(token);
r.activity.mConfigChangeFlags |= configChanges;

StopInfo info = new StopInfo();
performStopActivityInner(r, info, show, true);

if (localLOGV) Slog.v(
TAG, "Finishing stop of " + r + ": show=" + show
+ " win=" + r.window);

updateVisibility(r, show);

info.activity = r;
info.state = r.state;
info.persistentState = r.persistentState;
mH.post(info);
mSomeActivitiesChanged = true;
}
我们再来看方法performStopActivityInner实现
private void performStopActivityInner(ActivityClientRecord r,
StopInfo info, boolean keepShown, boolean saveState) {
// Next have the activity save its current state and managed dialogs...
if (!r.activity.mFinished && saveState) {
if (r.state == null) {
callCallActivityOnSaveInstanceState(r);
}
}

if (!keepShown) {
try {
// Now we are idle.
r.activity.performStop();
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
"Unable to stop activity "
+ r.intent.getComponent().toShortString()
+ ": " + e.toString(), e);
}
}
r.stopped = true;
}


我们知道saveState穿进去为true,只要mFinished不是true就一定进入这个方法,所以只要在mFinished不为true,也就是没有调用finish()函数的前提下,就一定执行onSaveInstanceState方法,所以当App设置的targetVersion大于android3.0,没有调用finish函数的情况下,一定会调用onSaveInstanceState方法后再去调用onStop方法。

3、为什么按Home键盘会掉用onSaveInstance方法保存数据,按Back不掉用onSaveInstance方法保存数据

因为按下Home键盘没有调用 finish函数,如果targetVersion大于Androi3.0就一定执行onSaveInstanceState方法,所以就保存数据了,如果按下返回键,会调用 finish方法,所有mFinished为true,所以不会掉用onSaveInstanceState方法,所以不会保存数据。




4、手机常见操作Activity生命周期状态变化来验证

写了一个简单的Activity,在每个Activity周期函数里面打印了相关的执行函数信息

1)、启动Activity



2)、按下电源或者Home键



3)、按亮电源键或者点击项目(一开启按了Home键)



4)、按下返回键(back键盘)





5、总结

1、onSaveInstanceState方法是Activity的生命周期方法,主要用于在Activity销毁时保存一些信息。

2、当Activity只执行onPause方法时(Activity a打开一个透明Activity b)这时候如果App设置的targetVersion大于android3.0则不会执行onSaveInstanceState方法。

3、当Activity执行onStop方法时,通过分析源码我们知道只要Activity没有执行finish函数一定会调用onSaveInstanceState的方法,然后再去掉用onStop方法。

onPause() ->  onSaveInstanceState() -> onStop()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: