本文为Android开发艺术探索的笔记,仅供学习
1 android的典型与异常生命周期分析
1.1 典型生命周期分析
七个生命周期函数
- onCreate(): 做一些初始化的工作,会调用setContentView去加载布局资源,如果bundle有数据可以获取
bundle里的数据(一般是在onSaveInteneceState去储存bundle) - onRestart():一般是再次启动是调用
- onStart():可以理解为显示视图,当前Activity在可见进程,可见但不可交互
- onResume():可以理解为获取焦点,当前Activity在前台进程,可见可以交互
- onPause():可以理解为失去焦点消失焦点 可以来储存一些信息 对象不能太大 否则会影响到下一个页面的显示
- onStop():可以理解为消失视图
- onDestroy():Activity的销毁
几种生命周期函数调用的情况
- 当打开Activity A 的时候 会调用 onCreate(A) onStart (A)onResume(A)
- 当前是在A页面,要打开新的Activity B 或者返回桌面的时候,
会调用 onPause (A) onCreate(B) onStart (B)onResume(B) onStop(A)
注: 如果A是采用透明主题 则不会调用onStop - 当用户返回A 的时候(或者按BACK) 会调用 onPause (B) onRestart(A) onStart (A)onResume(A) onStop(B)onDestroy(B)
对于整个生命周期来说 onCreate~onDestroy onStart~onStop onResume~onPause 这些都是一一对应的
1.2 异常生命周期分析
1.2.1 资源相关的系统配置发生改变导致Activity被杀死并重新建立
比如我们要去加载一张图片,我们先要把图片放在Drawable的文件夹下面,想要去加载图片,需要通过Resources去获取这张图片,我们在放图片的同时,需要根据不同的手机分辨率把图片放在想要的分辨率的Drawable的文件夹下面。当我们没有去设备Activity的configchange的时候,Activity的反转会导致Activity会被销毁并且重新加载如果我们不做处理,默认的生命周期是如下图
onSaveInstanceState的作用就是 可以通过bundle来存储一些数据 当Activity被销毁且重新创建的时候会去调用,onCreate 和onRestoreInstanceState 的方法去获取 onSaveInstanceState用来储存数据的对象bundle,从而去恢复被销毁前保留的信息。
注:onSaveInstanceState的调用时机是在onStop之前,与onPause没有时序关系,并且正常情况下是不调用onSaveInstanceState,仅在Activity被异常终止的时候调用。
我们在调用onSaveInstanceState的同时要理解,系统会默认帮我们保存当前的View的视图结构,比如文本框输入的信息,Listview滚动的位置等。
下面我们来看下Textview的源码
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);
//SavedState 是用于保存状态的
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;
}
1.2.2 资源内存不够导致低优先级被Activity被杀死
首先我们需要了解几个进程
- 前台进程:前台进程是Android系统中最重要的进程,是与用户正在交互的进程
- 可见进程:可见进程指部分程序界面能够被用户看见,却不在前台与用户交互。
- 服务进程:一个包含已启动服务的进程就是服务进程,服务没有用户界面,不与用户直接交互,但能够在后台长期运行,提供用户所关心的重要功能
- 后台进程:已被暂停的Activity,比如执行了onStop
- 空进程:空进程是不包含任何活跃组件的进程。在系统资源紧张时会被首先清除。
优先级从左到右 从大到小
前台进程>可见进程>服务进程>后台进程>空进程
因此对于一些独立运行在后台的进程很容易被杀死,所以就要把进程放在Service中,可以保证进程的优先级。
2 启动模式分析
2.1 四种启动模式分析
启动模式 一共有四个 standard(标准模式) singleTask(栈内复用模式) singleTop(栈顶复用模式)singleInstantce(单实例模式)
- standard:每启动一次就会重写创建一个新的实例,无论这个实例是否存在都会创建。如 a启动b 那边b会添加到a的栈内,栈内为 a b,重复添加b,那么栈内为 a b b b
- singleTop:栈顶复用模式,也就是说当前栈内是ABC 若要再次启动C(C为singleTop模式)则C不会再创建,因为栈顶的C已经存在了。 栈列 ABC 当前栈内是ABD 若启动C(C为singleTop模式)则C会再创建 栈内为ABDC。也就是说当栈顶不是要启动的对象,则会重新创建就等于standard模式 ,若栈顶和要启动的对象一样则不再创建。
- singleTask:
注:当启动模式为singleTask和singleTop的时候,该模式下的Activity被切换到栈顶的时候,会调用onNewIntent
- singleIntance: 当前有A B C,C的启动模式是singleIntance,这三个Activity 先启动A ,A添加到任务栈1中,在启动C,C则添加到任务栈2中,在启动B,B添加到任务栈1中,现在有两个任务栈 1和2 ,1中有A B,2中有C当第一次按Back的时候,任务栈1中的B退出,再按一次Back,A退出,最后才是C退出。 当被设置为该模式下(singleIntance)的时候,都会被添加到新的任务栈中去
任务栈其实是有名字的,一般默认为应用的包面,但是可以通过TaskAffinity去设置任务栈的名字
<activity android:name=".Okhttp_downapk" android:taskAffinity="com.abc.task1"/>
- 当TaskAffinity和SingleTask结合使用的时候,则该模式下的Activity启动的时候,会被添加到与TaskAffinity相同的任务栈中去
- 当TaskAffinity和allowTaskReparenting结合使用的时候,会产生特殊的效果。
举个例子,应用A启动了应用B的 C Activity,且C Activity的allowTaskReparenting为true的时候,然后按Home,在去点击应用B,则应用B显示的会是C Activity,C会从应用A的堆栈中移到应用B的堆栈中去。
2.2 Activity的Flags
使用如下
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
直接上图 书中分析的很详细