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

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()




你可能感兴趣的:(Android,进阶,onSaveInstance,onStop,onPause,home)