Android的生命周期是一个老生常谈的问题了,本文主要从典型情况下的生命周期以及异常情况下的生命周期来分析
一,典型情况下的生命周期
Android Activity生命周期主要分为以下几个部分:
1.onCreate()
生命周期的第一个方法,表示Activity被创建,整个生命周期中只会被触发一次,可以在该生命周期做一些基本的初始化操作,如setContentView等。
2.onRestart()
表示Activity正在重新启动,当当前Activity从不可见到可见状态,该方法会被调用,这种情况一般是用户行为导致,比如用户Home键返回到桌面,或者打开另外一个Activity时,当前Activity就会执行onPause和onStop,当再次回到当前Activity时候,onRestart就会被执行。
3.onStart()
表示Activity正在被启动,即将开始,这时候Activity已经可见了,但是还没有出现在前台,可以理解为已经显示出来了,但是还无法和用户交互。
4.onResume()
表示Activity已经可见了,并且出现在前台并开始活动了,与onStart相比,都表示可见,onResume表示在前台,onStart表示还在后台,一般紧随onStart之后出现。
5.onPause
表示Activity正在停止,正常情况下,onStop会紧随其后,特殊情况下如果快速的回到前台,onResume会被调用,这种属于极端情况,用户很难复现,在此方法内可以做一些简单的存储数据工作或者停止动画等工作,但是不可以太耗时,onPause必须执行完,onResume才会执行,太耗时会导致新的Avtivity显示。
6.onStop()
表示Activity即将停止,可以做一些回收工作,同样不能太耗时。
7.onDestroy()
表示Activity即将销毁,这是Activity生命周期中的最后一个回调,在这里,我们可以做一些回收工作和最终资源的释放。
正常情况生命周期只有上述7个,如下图,更加详细的描述了生命周期切换的过程

从上图可以看到,onStart和onStop 以及onPause和onResume看起来描述和功能都差不多,实际使用过程中也确实是使用其中一对即可,二者主要是onStart和onStop是从是否可见来表述,而onPause和onResume是从是否在前后台的角度来说明的,除了这个区别,二者没有其他明显区别。
如果当前Activity打开一个新的Activity,是当前Activity的onPause先执行,还是新Activity的onResume先执行呢?这里先说结论,是当前Activity的onPause先执行完,才会执行新Activity的onPause,有兴趣的可以看下源码ActivityStack中的resumeTopActivity-InnerLocked相关代码,并且可以写一个demo试试最终的效果。这也佐证了上面说到的onPause中不宜执行太过耗时的操作。
二,异常情况下的生命周期
Activity除了受到用户操作改变所导致的正常生命周期改变,还有一些异常情况,比如当前资源相关的系统配置发生改变,以及系统内存不足时,Activity就可能被杀死。
1.资源相关的配置发生改变导致Activity被杀死导致重建
比较常见的一种情况是横竖屏切换,在默认情况下,Activity就会被销毁并重建,当然也可以通过配置阻止重新创建Activity

当系统配置发生改变的时候,Activity会被销毁,按照正常的生命周期执行pause stop destroy等,同时Activity是异常情况下终止的,系统还会调用onSaveInstanceState来保存当前状态,需要注意的是,onSaveInstanceState在时序上,是在onStop之前,但是与onPause没有既定的时序关系,既可能在onPause之前,也可能在onPause之后,同时,onSaveInstanceState只会在Activity被异常终止的情况下触发,当Activity被重建时,系统会调用onRestoreInstanceState,并把销毁时onSaveInstanceState保存的Bundle对象作为参数传递给onRestoreInstanceState和onCreate,因此我们可以通过onRestoreInstanceState和onCreate方法来判断Activity是否被重建,如果重建了就可以取出之前保存的数据并恢复,从时序上来讲onRestoreInstanceState的调用时机在onStart之后。
同时,系统也会自动帮我们做一些恢复工作,比如文本框中输入的数据,ListView滚动的位置等,查看TextView源码可以看到,都有onSaveInstanceState和onRestoreInstanceState方法
@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;
}
@Override
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 (mSpannable != null) {
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(mSpannable, 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);
}
}
针对onSaveInstanceState还有一点需要注意的是,只有当Activity即将被销毁并且有机会重新显示的时候才会被调用,也就是说正常销毁的时候,系统不会调用onSaveInstanceState,因为被销毁的Activity不会再次被显示,这里可以拿旋转屏幕来参考,旋转屏幕时候,Activity有机会再次立刻展示,所以系统需要存储数据,而正常销毁Activity,不会再次显示,就不会触发onSaveInstanceState存储数据了。
2.资源内存不足,低优先级的Activity被杀死
这种情况不好模拟,但是其数据存储和恢复过程与1完全一致
Activity的优先级主要有3种:
1.前台Activity--正在和用户交互的Activity 优先级最高。
2.可见但非前台Activity--比如Activity弹出了一个对话框,导致Activity可见但是位于后台无法直接和用户交互。
3.后台Activity--已经被暂停的Activity,比如执行了onStop优先级最低。
当系统内存不足时,会按照上述优先级去杀死目标Activity所在的进程,并且后续通过onSaveInstanceState和onRestoreInstanceState去保存和恢复数据,如果一个进程中没有四大组件在执行,那么这个进程就很容易被系统杀死,因此一些后台工作不适合脱离四大组件独自运行在后台中,比较好的方法是将后台工作放到Service中从而保证有一定的优先级,不会轻易被系统杀死。
如果当系统配置改变的时候,我们不希望Activiy重新创建,这时我们就需要AndroidMenifest.xml中指定configChanges
android:configChanges="orientation|screenSize"
多个配置可以用"|"连接起来,系统中配置的属性非常多,这里不详细列举
至此,Activity的生命周期就介绍完了。
本文详细探讨了Android中Activity的生命周期,包括典型情况下的启动、暂停、停止和销毁过程,以及在异常情况如配置变化和内存不足时Activity的生命周期变化。文章还介绍了如何通过onSaveInstanceState和onRestoreInstanceState进行数据的保存和恢复。
836

被折叠的 条评论
为什么被折叠?



