在屏幕旋转Activity重建时 测试环境:Android10 一加6 onSaveInstanceState的展示时机跟其他文章有出入
D/PRETTY_LOGGER: │ MainActivityX onPause
D/PRETTY_LOGGER: │ MainActivityX onStop
D/PRETTY_LOGGER: │ MainActivityX onSaveInstanceState
D/PRETTY_LOGGER: │ MainActivityX onDestroy
重建后:
D/PRETTY_LOGGER: │ MainActivityX onCreate
D/PRETTY_LOGGER: │ MainActivityX onStart
D/PRETTY_LOGGER: │ MainActivityX onRestoreInstanceState
D/PRETTY_LOGGER: │ MainActivityX onResume
屏幕旋转,默认情况下Activity会进行重建。
避免Activity重建:
给 Activity添加android:configChanges="orientation|screenSize"属性
或者禁止旋转 android:screenOrientation=“portrait” 或者在代码中添加
fun onSaveInstanceState(outState: Bundle)
作用:保存信息和数据 在onDestroy()之前调用
被调用的时机 :当前界面息屏、Home键、屏幕旋转
fun onRestoreInstanceState(savedInstanceState: Bundle)
作用:可以用作恢复数据疑问:onCreate()里也有Bundle数据可以初始化,有什么不同? 在onStart()和onResume()之间调用。onCreate中的Bundle可能为空,根据需求选择数据恢复时机在哪。
疑问:都说Intent的Bundle传递数据量最大是1M-8K,那么保存的Bundle的数据也受限制吗?根据他人的描述,可能会出现问题,所以还是使用相同的解决方法,将数据放在数据库或者文件等形式保存
疑问:Activity的onSaveInstanceState保存了什么?
Activity.java
//保存了View树和Fragment的数据
protected void onSaveInstanceState(@NonNull Bundle outState) {
//View树的数据
outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
outState.putInt(LAST_AUTOFILL_ID, mLastAutofillId);
//Fragment的数据
Parcelable p = mFragments.saveAllState();
if (p != null) {
outState.putParcelable(FRAGMENTS_TAG, p);
}
if (mAutoFillResetNeeded) {
outState.putBoolean(AUTOFILL_RESET_NEEDED, true);
getAutofillManager().onSaveInstanceState(outState);
}
dispatchActivitySaveInstanceState(outState);
}
最终执行到:
View.java
protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) {
mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;
Parcelable state = onSaveInstanceState();
if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) {
throw new IllegalStateException(
"Derived class did not call super.onSaveInstanceState()");
}
if (state != null) {
// Log.i("View", "Freezing #" + Integer.toHexString(mID)
// + ": " + state);
container.put(mID, state);
}
}
}
@Nullable protected Parcelable onSaveInstanceState() {
mPrivateFlags |= PFLAG_SAVE_STATE_CALLED;
if (mStartActivityRequestWho != null || isAutofilled()
|| mAutofillViewId > LAST_APP_AUTOFILL_ID) {
BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE);
if (mStartActivityRequestWho != null) {
state.mSavedData |= BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED;
}
if (isAutofilled()) {
state.mSavedData |= BaseSavedState.IS_AUTOFILLED;
}
if (mAutofillViewId > LAST_APP_AUTOFILL_ID) {
state.mSavedData |= BaseSavedState.AUTOFILL_ID;
}
state.mStartActivityRequestWhoSaved = mStartActivityRequestWho;
state.mIsAutofilled = isAutofilled();
state.mAutofillViewId = mAutofillViewId;
return state;
}
return BaseSavedState.EMPTY_STATE;
}
使用例子:
TextView.java 重载onSaveInstanceState()
@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;
}
疑问:Activity里的Fragment要怎么处理?