Activity的启动过程是一个很复杂的过程,涉及了Instrumentation ActivityThread AMS(ActivityManagerService)等类。 ActivityThread和AMS之间的通信是跨进程的通信,采用的机制是Binder机制,具体就是利用ApplicationThread binder接口来完成。ApplicationThread是ActivityThread的内部类。
启动Activity的请求会有Instrumentation来处理,之后会通过binder向AMS来发送请求,AMS里面会又个ActivityStack来负责栈内的Activity状态的同步。启动Activity最终会调用到ActivityThread中的scheduleLaunchActivity方法。
有个问题: 当Activity A启动Activity B的时候,A的onPause需要先执行,然后Activity B才会启动。
Activity的生命周期:
生命周期可以分为两种:正常情况和异常情况。
正常情况的生命周期就不说了,主要说下异常的生命周期
当与资源相关的系统配置发生改变以及系统内存不足时,Activity就可能会被杀死,这种情况的生命周期是什么样的,主要讨论这种。
1.我们知道我们可以设置横屏和竖屏的资源,在手机处在横屏和竖屏的情况去不同的文件夹中加载资源,这时Activity就会被重新创建
2.当系统内存不足时,系统也会杀死后台的Activity,当应用回到这个Activity的时候,此Activity又会被重新创建
当异常情况,Activity被杀死的时候,onSaveInstanceState回调方法会被调用,在onStop之前,在此方法中可以保存下数据,当Activity恢复的时候,可以恢复数据。 在Activity被重新创建的是时候,onCreate和onRestoreInstanceState会被调用,且其参数bundle不为空,是Activity被杀死的时候存储的数据。
onSaveInstanceState和onRestoreInstanceState系统为我们有默认实现,可以恢复一些View的状态。每个View也有onSaveInstanceState和onRestoreInstanceState,这两个方法就用于恢复view状态的。
Activity—window—decorview—activity的contentview
前面说到系统内存不足的时候会杀死Activity,杀哪个Activity是根据Activity优先级的。
1.前台Activity,可交互的,优先级最高
2.可见的Activity,但不可交互
3.后台Activity,不可见的最低
当一个应用没有四大组件的时候后台会很快杀死这个进程。
可以通过设置Activity,当资源发生变化的时候不重建Activity。用android:configChanges=“”来设置,例如设置当屏幕方向改变时不重建,就android:configChanges=“orientation”。多个值使用“|”分割。
比较常用的有locale orientation keyboardHidden screenSize
Activity的启动模式
Activity有四种启动模式: standard singleTask singleTop singleInstance
standard:默认模式,可以有多个实例,谁启动了这个Activity,这个Activity就运行在谁的任务栈中。
注:当用Application的Context用标准模式去启动Activity的时候,会报错。因为 Application的Context没有任务栈,只有Activity的Context才有任务栈,而标准方式启动的Activity要运行在Caller的任务栈中,所以报错了。这时可以使用SingleTask方式启动。
singleTop:栈顶复用模式,如果已经有实例在栈顶了,则不会创建新的实例,onNewIntent会被调用,如果栈顶的实例不是此Activity则创建新的实例。
singleTask:栈内服用模式,单例模式 只用Activity在一个栈中存在,则不会重新创建实例,会调用onNewIntent方法
singleInstance: 单实例模式,是singleTask的加强版。只能单独位于一个栈中。
这里要说到一个参数 TaskAffinity,任务相关性。这个参数标志了一个Activity所需要的任务栈的名字,默认情况下所有Activity所需的任务栈的名字是应用的包名,我们可以为每个Activity单独制定TaskAffinity属性,这样就可以运行在新的任务栈了。
TaskAffinity属性需要和singleTask或allowTaskReparenting属性配对使用。其他情况没有意义。
TaskAffinity和singleTask配合使用,可以是Activity在一个新的任务栈中。
TaskAffinity和allowTaskReparenting配合使用,可以是Activity转移
例如:应用A启动了应用B的Activity C,当再次启动应用B的时候,展示的不是launcher界面,而是Activity C。
有两种方式为Activity设定启动模式,manifest和代码动态指定。
用代码的方式的优先级要高于在manifest中指定。
这里介绍一个命令: adb shell dumpsys activity 查看任务栈里面的activity
Activity的Flags
1.FLAG_ACTIVITY_NEW_TASK相当于singleTask
2.FLAG_ACTIVITY_SINGLE_TOP相当于singleTop
3.FLAG_ACTIVITY_CLEAR_TOP清除上面的所有activity,如果是standard的,那么包含自己也清楚,之后在栈顶新建实例
4.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS不出现在历史列表中,和manifest中android_excludeFromRecents=“true”效果相同。
IntentFilter匹配规则
Activity的启动分为显示和隐式。显示需要指定包名和Activity名。而隐式则通过匹配IntentFilter。
下面只说隐式启动:
IntentFilter的过滤信息有action category data,为了匹配IntentFilter,需要同时匹配action category 和 data信息,否则匹配失败。一个过滤列表中的aciton category data可以有多个,所有的action category data分别构成不同的类别,同一类别的信息共同约束当前类别的匹配过程。只有一个Intent同时匹配action类别、category类别、data类别才算完全匹配,只有完全匹配才能启动成功目标Activity。一个Activity可以有多个IntentFilter,一个Intent只要能匹配一组IntentFilter即可成功启动。
下面分别说各组匹配规则:
aciton:
一个Intent中的action能和IntentFilter的任意一个相同即可匹配成功。如果Intent中没有action,则匹配失败,即Intent中action必须有。
category:如果Intent中设定了category,那么要求不论设置几个,都需要和IntentFilter匹配。同时如果Intent没设置category,在startActivity或startActivityForResult中,会默认给Intent添加category“android.intent.category.DEFAULT”,这样如果IntentFilter中有这个category,也是可以匹配的。
data:
如果IntentFilter定义了data,那么Intent必须匹配。
先说下data的结构
data由两部分组成:mimeType和URI,mineType指媒体类型,比如image/jpeg、audio/mpeg4-generic和vido/*等,可以表示图片文本视频等不同媒体格式,
下面看下URI的结构
://:/[||]
例如:content://com.example.project:200/folder/subject/etc
scheme:URI模式,比如http file content,如果没有指定scheme,那么整个URI无效
Host: URI的主机名。如果没有指定Host,那么URI无效
Port:端口号。仅当URI中指定了scheme和Host,port才有意义
path pathPattern pathPrefix表示路径信息。pathPattern可以使用“*”,表示0个或多个任意字符,pathPrefix表示路径前缀信息
data的匹配规则要求Intent中必须含有data,并且能够完全匹配IntentFilter中的某一个data
IntentFilter中的URI有默认值,是content和file
注意:Intent指定完整data的时候要使用setDataAndType,而不能分开使用setData,setType,因为这两个方法会清空对方的值。
IntentFilter的匹配规则也使用BoradcastReceiver和Service。
可以使用PackageManager中的resolveActivity和queryIntentActivitys判断,intent能否有匹配的Activity
注意:由于在startActivity和startActivityForResult中会默认添加default的category,根据category的匹配规则,可以知道只有IntentFilter声明了default 的category,才能被隐式的调用。