牛骨文教育服务平台(让学习变的简单)

最近想写篇关于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如下

http://www.baidu.com:80/search/info

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启动源码的理解。