最近想写篇关于Activity启动过程源码分析的博客,在此之前先总结下Android中Activity必须要知道的一些基础知识,以方便后面能看懂Activity的源码。
一,Activity生命周期和启动模式
activity最经典的启动模式图如下:
它分为
onCreate--onStart--onResume--onPause--onStop--onDestory.这几个阶段,这个是个android开发者肯定都很熟悉,这里不详细说,只是说下一些注意事项:
1.onStart和onStop的区别:onStart表示应用己经可见,但只运行在后台,没到前台。onStop表示acitvity运行在后台。当用户使用透明主题,不会调用onstop.
2.onResume和onpause的区别:这两个是从activity是否位于前台来回调的,是一组。
3.当新Activity启动之前,栈顶acitivity需要先onPause新的再启动。所以不能在onpause中做耗时操作。
4.当activity异常停止时,会调用onSaveInstanceState,并把所保存的Bundle传递给onRestoreInstanceState,onRestoreInstanceState是在onStart之后被调用。过程是onSaveInstanceState先保存数据,Activity会委托Window保存数据,接着Window再委托上面的顶级容器去保存,一直往上委托直到DecorView,最后它再一一通知它的子元素来保存数据。典型的委托思想。
如果onRestoreInstanceState被调用 ,那它的onSaveInstanceState参数一定有值。
5.在资源不足情况下导致的activity被杀死也会调用onSaveInstanceState。activity有三个优先级:
* 前台activity。
* 可见但非前台activity(如Dialog)
* 后台activity(onstop的情况)。
二,启动模式
1.启动模式介绍:
android有四种模式,分别是standard,singleTop,singleTask,singleInstance。
standard:一个任务栈可以有多个实例,每个实例可以属于不同任务栈。每新建一个activity就新建一个实例。一个实例被哪个实例创建,就存在哪个实例所在的栈中,如A启动了B,那么B就位于A的栈中。不能在appliactionContext中启动它,因为非activity的context没有任务栈,解决方法是加上FLAG_ACTIVITY_NEW_TASK标识,会新建一个任务栈。
singleTop:如果activity存在栈顶,此时activity不会被重建,它的oncreate等方法不会被重调用 。如栈中有ABC,再启动C,就不会重新创建C。
singleTask:栈内复用模式,首先判断所需要的栈是否在否存在,若存在,那么只要在栈中存在,就不新建实例,并cleanTop,如果不存在,新建实例。如果所要的栈都不存在,新建栈。
如栈中有ABCD,启动C,C指定了所需的栈且栈不存在,那么就会创建一个新栈,并把C存入,此时就存在两个栈,一个是ABC,一个是C。如栈中有ABCD,启动的C所需的栈就是ABCD所在的栈,那就会把C置于栈项,C上的所有实例出栈,此时栈就变成了ABC。那么如何指定所需任务栈。一般使用TaskAffinity来指定,下面会说明。
singleInstance:具有singleTask的所有特性。不同的是,具有此模式的acitivity只能单独位于一个栈中。如创建了A,A在一个栈中,后续再创建A就不会再创建实例了。
指定启动模式有两种设置方法:
在xml中设置:andorid:launchMode="singleTop"
在代码中设置:intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);这种方法的优点是优先级比第一种高,比如同时用两种方法设置,那以第二种为主,缺点是它不能设置singleInstance。
2.所需任务栈:
TaskAffinity:标识了一个activity所需要的任务栈名称。默认为应用的包名。主要和singleTask配对使用。
任务栈分为前台和后台任务栈。后台 任务栈是指位于暂停的状态。用户可以切换将后台再次调到前台。
A启动B,则B会位于A的任务栈中。(没有TaskAffinity情况下)
比如A启动B,B的TaskAffinity与A的不同,那就会创建新任务栈并把B放入。
AB是前台栈,CD是后台栈,B启动D,则变成ABCD,启动C则变成ABC.
3.标志位:
我们经常会在代码中指定标志位,主要的标志位有以下几种:
FLAG_ACTIVITY_NEW_TASK:类似singleTask
FLAG_ACTIVITY_SINGLE_TOP:类似singleTop
FLAG_ACTIVITY_CLEAN_TOP:清当前activity栈中它本身以上的activity
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:具有这个标记的activity不会出现在历史activity列表中。只需设置
android:excludeFromRecents="true"
三,IntentFilter匹配规则
启动activity有显式和隐式两种,如果是隐式,就要满足
IntentFilter匹配规则。
intent 有action,category,data.三个属性。只有一个intent同时匹配了action,category和data才算完全匹配。有多个filter只要有一个匹配就可以。
action只要有一个匹配就可以。
category:如果intent有这个属性,那它所有的category都必须匹配上。可以没有。没有默认有DEFAULT这个属性。为了我们的activity能接受隐式调用,就必须加上android.intent.category.DEFAULT这个属性。
data:与action类似。它为分为两部分。mimeType,URL.mineType指媒体类型,如image/jpeg等,URL如下
URL默认是content和file,在不指定data 情况下就是匹配它。调用的方法如下
intent.setDataAndType(Uri.parse("file://abc"),"image/png")
完整的代码如下:
Intent intent = new Intent("com.lxj.a");
intent.addCategory("com.lxj.b");
intent.setDataAndType(Uri.parse("file://abc"),"image/png")
startActivity(intent);
匹配的是如下的activity
<activity …………>
<intent-filter>
<action android:name="com.lxj.a"/>
<actegory android:name="com.lxj.b"/>
<actegory android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
<data android:mimeType="image/*"/>
</intent-filter>
<activity/>
就先写这么多吧,下一篇我会介绍下我对activity启动源码的理解。