虽然我这博客也没几个人看,但还是要坚持写下去,域名也买了,所以今年目标的其中一个就是做好我的个人页面,近期先链接到Csdn这里,www.tiandroid.com这就是我未来的个人主页,敬请期待。。。
今天呢就写点关于Activity的简单的东西,生命周期和启动模式。关于Activity比较复杂的便是启动流程,会在以后慢慢更新,也许是下周,也许是。。。
实际上想起写这东西是因为偶然看到了一个面经
E:“onSaveInstanceState什么时候调用?”
m:“按Home键。。。或者。。。”
E:“按Home键就要调用onSaveInstanceState,那岂不是应用只要返回前台就要调用onRestoreInstanceState?这么麻烦吗”
m:“。。。”
这两个东西到底什么时候调用呢?是不是save了就要restore呢?他们和生命周期有什么关系?
不再扯废话了,开始第一部分:
生命周期就和人的生命一样,可以分为健康的时候和生病的时候,对应着
首先说典型情况,
那这里免不了放一张官方的图
这个图我就不多解释了,只说一些注意情况
正常情况下的特例或者是需要特殊记得点就这么多,如果还有特殊的请留言。
那么接下来我们看一下异常情况下的生命周期
异常下无论哪种都会经历以下流程
有异常状况,Activity销毁,重建,并对应着onSaveInstanceState,onRestoreInstanceState来储存和恢复数据。
这个异常状况分两种
第一种情况,内存不足时候不出众的Activity就被干死了。。。
以“出众”作为评价标准大致分为三种:
第二种情况,资源相关的系统配置变了
比如我旋转了屏幕,竖屏变成了横屏,配置变了,就只能按上面的图重新来过。
过程不难,但是重点是提到的两个回调方法onSaveInstanceState,onRestoreInstanceState,下面就从源码来看到底里面做了什么操作
先看一段介绍
* This method is called before an activity may be killed so that when it
* comes back some time in the future it can restore its state. For example,
* if activity B is launched in front of activity A, and at some point activity
* A is killed to reclaim resources, activity A will have a chance to save the
* current state of its user interface via this method so that when the user
* returns to activity A, the state of the user interface can be restored
* via {@link #onCreate} or {@link #onRestoreInstanceState}.
*
If called, this method will occur before {@link #onStop}. There are
* no guarantees about whether it will occur before or after {@link #onPause}.
就是说onSaveInstanceState方法会在Activity被kill之前执行。一定是在onStop之前,不确定在onPause前或后。
来看源码onSaveInstanceState(Bundle outState)
:
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);
}
分两步走
这两个都是通过保存根View的状态来实现的,所以我们从mWindow.saveHierarchyState()
开始看起,Window的唯一实现类是PhoneWindow(我怎么知道的?是在看事件分发机制的时候,事件分发也挺有意思,有空写写),所以就去PhoneWindow里找到
public Bundle saveHierarchyState() {
Bundle outState = new Bundle();
if (mContentParent == null) {
return outState;
}
SparseArray states = new SparseArray();
mContentParent.saveHierarchyState(states);
outState.putSparseParcelableArray(VIEWS_TAG, states);
// Save the focused view ID.
final View focusedView = mContentParent.findFocus();
if (focusedView != null && focusedView.getId() != View.NO_ID) {
outState.putInt(FOCUSED_ID_TAG, focusedView.getId());
}
// save the panels
SparseArray panelStates = new SparseArray();
savePanelState(panelStates);
if (panelStates.size() > 0) {
outState.putSparseParcelableArray(PANELS_TAG, panelStates);
}
if (mDecorContentParent != null) {
SparseArray actionBarStates = new SparseArray();
mDecorContentParent.saveToolbarHierarchyState(actionBarStates);
outState.putSparseParcelableArray(ACTION_BAR_TAG, actionBarStates);
}
return outState;
}
来起来比较多,但实际就是
mContentParent.saveHierarchyState(states);
点进去看一下 public void saveHierarchyState(SparseArray container) {
dispatchSaveInstanceState(container);
}
protected void dispatchSaveInstanceState(SparseArray 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);
}
}
}
实际上调用的是dispatchSaveInstanceState,开头可以看到他只存了有Id的,还是很聪明的,我们还是看重点,其中核心为onSaveInstanceState();
protected Parcelable onSaveInstanceState() {
mPrivateFlags |= PFLAG_SAVE_STATE_CALLED;
if (mStartActivityRequestWho != null) {
BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE);
state.mStartActivityRequestWhoSaved = mStartActivityRequestWho;
return state;
}
return BaseSavedState.EMPTY_STATE;
}
这个方法检查了一下mStartActivityRequestWho这个String对象是否为null,mStartActivityRequestWho这个对象只有在调用了View#startActivityForResult时才会设置,这时标记一下state中的状态,为null时,直接返回一个空状态。
总结一下,saveHierachyState()方法直接传递给了dispatchSaveInstanceState()方法。dispatchSaveInstanceState()是分发保存状态这个事件,它默认是在有ID的情况下保存自身的state,没有id就拉倒。上面看的是View类的方法,实际mContentParent是个ViewGroup,我们知道ViewGroup是View的子类,所以ViewGroup和其他控件类可以重写这个方法,将保存状态的行为分发到子类中。onSaveInstanceState()方法用来具体地保存当前View的状态。所以看一下ViewGroup的分发
protected void dispatchSaveInstanceState(SparseArray container) {
super.dispatchSaveInstanceState(container);
final int count = mChildrenCount;
final View[] children = mChildren;
for (int i = 0; i < count; i++) {
View c = children[i];
if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
c.dispatchSaveInstanceState(container);
}
}
}
首先调用View#dispatchSaveInstanceState()保存自己,然后遍历子View,调用对应的dispatchSaveInstanceState()方法,然后通过各个控件的重写onSaveInstanceState保存。下面举个例子,看一下TextView#onSaveInstanceState()是怎么保存状态的:
public Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
// Save state if we are forced to
boolean save = mFreezesText;
int start = 0;
int end = 0;
if (mText != null) {
start = getSelectionStart();
end = getSelectionEnd();
if (start >= 0 || end >= 0) {
// Or save state if there is a selection
save = true;
}
}
if (save) {
SavedState ss = new SavedState(superState);
// XXX Should also save the current scroll position!
ss.selStart = start;
ss.selEnd = end;
if (mText instanceof Spanned) {
Spannable sp = new SpannableStringBuilder(mText);
if (mEditor != null) {
removeMisspelledSpans(sp);
sp.removeSpan(mEditor.mSuggestionRangeSpan);
}
ss.text = sp;
} else {
ss.text = mText.toString();
}
if (isFocused() && start >= 0 && end >= 0) {
ss.frozenWithFocus = true;
}
ss.error = getError();
if (mEditor != null) {
ss.editorState = mEditor.saveInstanceState();
}
return ss;
}
return superState;
}
从上述源码中很容看出他保存了文本的选中状态和文本的内容,end。
总结一下吧:
1.在Activity被回收时,会触发一个onSaveInstanceState的事件;
2.分发事件,onSaveInstanceState事件从Activity->Window(PhoneWindow)->顶级ViewGroup(一般是DecorView)->一一通知子元素保存;
3.以View的ID作为key存起来。
会看整个内容,有很多关键词在Android中有很多的应用,比如:dispatch、PhoneWindow、DecorView等等,可以联系起很多具有这种分发委托思想的结构,像事件分发、View绘制等等都是类似的,所以学好学透一个会对以后学习其他的有很大帮助。
回到最开始的问题,因为onSaveInstanceState是在Activity销毁之前调用,任何会被认为将要销毁的操作都可以触发onSaveInstanceState,情况还不少呢,那每次save都会调用onRestoreInstanceState,这么麻烦的吗?
当然不会,虽然他俩名字很像,但其实并不是配套出现的
protected void onRestoreInstanceState(Bundle savedInstanceState) {
if (mWindow != null) {
Bundle windowState = savedInstanceState.getBundle(WINDOW_HIERARCHY_TAG);
if (windowState != null) {
mWindow.restoreHierarchyState(windowState);
}
}
}
它的原理就是把存了的数据拿出来,调用PhoneWindow的restoreHierarchyState(windowState)
public void restoreHierarchyState(Bundle savedInstanceState) {
if (mContentParent == null) {
return;
}
SparseArray<Parcelable> savedStates
= savedInstanceState.getSparseParcelableArray(VIEWS_TAG);
if (savedStates != null) {
mContentParent.restoreHierarchyState(savedStates);
}
// restore the focused view
int focusedViewId = savedInstanceState.getInt(FOCUSED_ID_TAG, View.NO_ID);
if (focusedViewId != View.NO_ID) {
View needsFocus = mContentParent.findViewById(focusedViewId);
if (needsFocus != null) {
needsFocus.requestFocus();
} else {
Log.w(TAG,
"Previously focused view reported id " + focusedViewId
+ " during save, but can't be found during restore.");
}
}
// Restore the panels.
SparseArray<Parcelable> panelStates = savedInstanceState.getSparseParcelableArray(PANELS_TAG);
if (panelStates != null) {
restorePanelState(panelStates);
}
if (mDecorContentParent != null) {
SparseArray<Parcelable> actionBarStates =
savedInstanceState.getSparseParcelableArray(ACTION_BAR_TAG);
if (actionBarStates != null) {
doPendingInvalidatePanelMenu();
mDecorContentParent.restoreToolbarHierarchyState(actionBarStates);
} else {
Log.w(TAG, "Missing saved instance states for action bar views! " +
"State will not be restored.");
}
}
}
就不多说了,和保存完全一样的,和之前一样还是看一下restoreHierarchyState(savedStates)
public void restoreHierarchyState(SparseArray container) {
dispatchRestoreInstanceState(container);
}
protected void dispatchRestoreInstanceState(SparseArray container) {
if (mID != NO_ID) {
Parcelable state = container.get(mID);
if (state != null) {
// Log.i("View", "Restoreing #" + Integer.toHexString(mID)
// + ": " + state);
mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;
onRestoreInstanceState(state);
if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) {
throw new IllegalStateException(
"Derived class did not call super.onRestoreInstanceState()");
}
}
}
}
实际上调用的是dispatchRestoreInstanceState,通过ID去拿数据,其中核心为onRestoreInstanceState();
protected void onRestoreInstanceState(Parcelable state) {
mPrivateFlags |= PFLAG_SAVE_STATE_CALLED;
if (state != null && !(state instanceof AbsSavedState)) {
throw new IllegalArgumentException("Wrong state class, expecting View State ");
}
if (state != null && state instanceof BaseSavedState) {
mStartActivityRequestWho = ((BaseSavedState) state).mStartActivityRequestWhoSaved;
}
}
就是直接拿到mStartActivityRequestWho,就和保存完全相反而已
再看一下ViewGroup的分发:
protected void dispatchRestoreInstanceState(SparseArray container) {
super.dispatchRestoreInstanceState(container);
final int count = mChildrenCount;
final View[] children = mChildren;
for (int i = 0; i < count; i++) {
View c = children[i];
if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
c.dispatchRestoreInstanceState(container);
}
}
}
依然是一样,遍历子View调用c.dispatchRestoreInstanceState
,对于控件要重写这个方法来实现获取数据,还是以TextView为例:
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);
}
}
可以看出量过程实际上完全相同。
从正常活着,到不正常死亡,再到死亡后重生,到此就算是讲完了Activity的生命了。