Activity你需要知道的一切

最后更新于:2022-04-01 14:26:11

最近想写篇关于Activity启动过程源码分析的博客,在此之前先总结下Android中Activity必须要知道的一些基础知识,以方便后面能看懂Activity的源码。 ### 一,Activity生命周期和启动模式 activity最经典的启动模式图如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-08_570771b66a3fc.jpg) 它分为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](http://www.baidu.com/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启动源码的理解。
';