onSaveInstanceState与onRestoreIns

2018-09-14  本文已影响0人  迷途之中小书童

如果没有对activity配置做处理,那么onSaveInstanceState会在手机系统配置发生变化时进行调用,例如手机横竖屏切换,用于保存当前activity状态,包括内部view中状态。这种状态下,activity会进行销毁并重建,activity生命周期会发生变化,调用顺序

onPause-->onStop-->onDestroy

由于系统是由于异常销毁,此时会先调用onSaveInstanceState方法,该方法会在onStop之前进行调用,但不一定在onPause之前或之后,然后在横屏后,activity调用onCreate进行重建,然后调用onRestoreInstanceState进行activity状态恢复。如果想要了解avtivity中view的状态缓存与恢复,可以看下view中的onSaveInstanceState方法的具体实现,这里就不粘贴出代码了,有兴趣的自行查看。
贴出activity由竖屏切换到横屏的声明周期变化

09-14 11:11:29.207 5716-5716/sunhailong01.myandroidp D/codebear: onSaveInstanceState
09-14 11:11:29.212 5716-5716/sunhailong01.myandroidp D/codebear: onStop
onDestroy
09-14 11:11:29.250 5716-5716/sunhailong01.myandroidp D/codebear: onCreate
09-14 11:11:29.263 5716-5716/sunhailong01.myandroidp D/codebear: onStart
09-14 11:11:29.335 5716-5716/sunhailong01.myandroidp D/codebear: onRestoreInstanceState
09-14 11:11:29.382 5716-5716/sunhailong01.myandroidp D/codebear: onResume

onSaveInstanceState调用栈如下

image.png

Avtivity的onSaveInstanceState的实现如下

protected void onSaveInstanceState(Bundle outState) {
outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
outState.putInt(LAST_AUTOFILL_ID, mLastAutofillId);
Parcelable p = mFragments.saveAllState();
if (p != null) {
outState.putParcelable(FRAGMENTS_TAG, p);
}
if (mAutoFillResetNeeded) {
outState.putBoolean(AUTOFILL_RESET_NEEDED, true);
getAutofillManager().onSaveInstanceState(outState);
}
getApplication().dispatchActivitySaveInstanceState(this, outState);
}

先说结论

子类avtivity委托父类activity进行状态缓存实现,而父类activity的onSaveInstanceState中委托给appllacation进行SaveInstanceState的事件分发,而Applaction委托windosw(为什么是window往后看会有解释)分发,windows最终会委托最顶层的view进行状态缓存事件分发,顶层view通知各内部子view进行具体事件分发的实现。

再看实现

Textview的onSaveInstance的具体实现如下

@Override
public Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
// Save state if we are forced to
final boolean freezesText = getFreezesText();
boolean hasSelection = false;
int start = -1;
int end = -1;
if (mText != null) {
start = getSelectionStart();
end = getSelectionEnd();
if (start >= 0 || end >= 0) {
// Or save state if there is a selection
hasSelection = true;
}
}
if (freezesText || hasSelection) {
SavedState ss = new SavedState(superState);
if (freezesText) {
if (mText instanceof Spanned) {
final Spannable sp = new SpannableStringBuilder(mText);
if (mEditor != null) {
removeMisspelledSpans(sp);
sp.removeSpan(mEditor.mSuggestionRangeSpan);
}
ss.text = sp;
} else {
ss.text = mText.toString();
}
}
if (hasSelection) {
// XXX Should also save the current scroll position!
ss.selStart = start;
ss.selEnd = end;
}
if (isFocused() && start >= 0 && end >= 0) {
ss.frozenWithFocus = true;
}
ss.error = getError();
if (mEditor != null) {
ss.editorState = mEditor.saveInstanceState();
}
return ss;
}
return superState;
}

最后贴出textView的onSaveInstanceState方法调用栈,一切就明了了

image.png

再来看下状态是如何恢复的

onRestoreInstanceState 调用栈如下

image.png

Avtivity的onRestoreInstanceState的实现如下

protected void onRestoreInstanceState(Bundle savedInstanceState) {
if (mWindow != null) {
Bundle windowState = savedInstanceState.getBundle(WINDOW_HIERARCHY_TAG);
if (windowState != null) {
mWindow.restoreHierarchyState(windowState); // 这里使用了window进行了状态恢复,所以状态的缓存最终也是通过window进行缓存事件分发
}
}
}

TextView的onRestoreInstanceState方法实现如下

public void onRestoreInstanceState(Parcelable state) {
if (!(state instanceof SavedState)) {
super.onRestoreInstanceState(state);
return;
}
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
// XXX restore buffer type too, as well as lots of other stuff
if (ss.text != null) {
setText(ss.text);
}
if (ss.selStart >= 0 && ss.selEnd >= 0) {
if (mText instanceof Spannable) {
int len = mText.length();
if (ss.selStart > len || ss.selEnd > len) {
String restored = "";
if (ss.text != null) {
restored = "(restored) ";
}
Log.e(LOG_TAG, "Saved cursor position " + ss.selStart + "/" + ss.selEnd
+ " out of range for " + restored + "text " + mText);
} else {
Selection.setSelection((Spannable) mText, ss.selStart, ss.selEnd);
if (ss.frozenWithFocus) {
createEditorIfNeeded();
mEditor.mFrozenWithFocus = true;
}
}
}
}
if (ss.error != null) {
final CharSequence error = ss.error;
// Display the error later, after the first layout pass
post(new Runnable() {
public void run() {
if (mEditor == null || !mEditor.mErrorWasChanged) {
setError(error);
}
}
});
}
if (ss.editorState != null) {
createEditorIfNeeded();
mEditor.restoreInstanceState(ss.editorState);
}
}

最后贴出textView的onRestoreInstanceState方法调用栈,一切就又明了了

image.png

至此,我们了解了onSaveInstance的调用时机、实现逻辑、调用顺序。

上一篇下一篇

猜你喜欢

热点阅读