Activity的生命周期和启动模式
典型情况下的生命周期
-
第一次启动:
onCreate()=>onStart()=>onResume() -
打开新的 Activity & 回到桌面:
onPause()=>onStop(),当使用透明主题的时候,Activity不会走onStop() -
用户回到原先的Activity:
onReStart()=>onStart()=>onResume() -
Back按钮回退:
onPause()=>onStop()=>onDestroy() -
Activity 被系统回收 生命周期如 1
-
onCreate()和OnDestroy()配对只被调用一次,onResume()和onPause()配对随着用户操作和熄亮屏操作调用多次,onStart()和onStop()同理。
onStart()和onStop()对和onResume()和onPause()的区别?
无明显区别,onStart()组跟后台相关,onResume()组针对于前台的显示相关,因为这两组生命周期直接和显示相关,不推荐在onPause()和onResume()做耗时操作。
注意:ActivityA 到 ActivityB A的onPause后 B才能显示
异常情况下的生命周期
-
资源相关的系统配置发生改变导致Activity被重建
这种情况比如 设备由横屏切换为竖屏,系统会应用不同情况下的图片资源,如Drawable-landscape,默认情况下系统会销毁当前的Activity并且重建Activity.
当重建发生时,
onPause(),onStop(),onDestroy()均会被执行,因为是异常情况终止,系统会调用onSaveInstanceState()来保存当前的状态,onSaveInstanceState()的调用时机在onStop()之前,与onPause()的调用没有关系,相同的被异常终止而重建的Activity会在onStart()后调用onRestoreInstanceState(),两个方法之间是由Bundle进行数据的交流,系统默认帮我们做了些处理,onSaveInstanceState()和onRestoreInstanceState()默认会帮我们保存和恢复诸如滚动视图的滑动位置,输入框的已输入内容等数据.具体的细节和过程可以查看Android源码. -
资源内存不足导致的低优先级Activity被杀死
Activity的优先级排序
- 前台正在显示的Activity
- 可见的非前台的Activity,如Activity弹出个全屏Dialog
- 后台Activity
同样的,被杀死后通过onSaveInstanceState()和onRestoreInstanceState()重建.
我想避免某些系统配置发生变化的时候重建Activity,该怎么操作呢?
可以指定Activity的android:configChanges = ""
具体的可以查询对应的参数列表,通过指定对应的场景不执行重建Activity,这时可以在Activity的onConfigurationChanged()回调中进行特殊处理.
Android的启动模式
-
standard:标准模式
每次使用该模式都会创建应该新的实例,该实例回执行完整的典型情况下的生命周期,该实例运行在启动它的的Activity的任务栈中.
为什么使用applicatioContext无法使用标准模式启动Activity呢?
因为application并没有自己的任务栈,无法存放这个新启动Activity的实例,通常回价格NEW_TASK的FLAG,实际上这步是使用SingleTask的方式启动了新的Activity,为其创建了一个新的任务栈.
-
singleTop:栈顶复用
如果新的Activity已经位于栈顶,则这个Activity不会被重建,但会触发onNewIntent,我们可以使用这个方法获取信息,这个Activity的
onCreate()和onStart()不会被重新调用,如果被启动Activity不位于栈顶,则依旧会重建. -
singleTask:栈内复用
如果这个Activit不存在,会创建这个Activity的实例,系统会确认这个Activity需要任务栈存不存在,不存在则会创建一个任务栈.与singleTask类似,但只要这个Activity在栈内存在就不会重建,同样的不会重走
onCreate()和onStart(),可以在onNewIntent中重新获取信息,实例不存在则会压入栈中.singleTop具有clearTop效果,如1号栈有Activity ABCD,B以SingleTask的方式启动,且B需要的任务栈也为1号栈,则系统会把当前前台Activity切回B,并将CD清除掉,因此最终结果是AB. -
singleInstance:单实例模式
该模式创建的Activity仅仅会存在与一个独立的任务栈中,一旦创建,之后的请求均不会创建新的该Activity对象,除非系统将这个栈销毁.
IntentFilter的匹配规则
启动Activity分为两种方式,显示启动和隐式启动.
显示启动通过指定启动对象的包名和类名来指定启动对象.
隐式调用,要求目标组建的IntentFilter的过滤信息可以匹配上intent,如果匹配则可以启动. IntentFilter中的过滤信息有action,category,data.
<intent-filter>
<action android:name="com.spica.a"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
匹配过滤信息列表,需要同时匹配所有的action,category,data.
action,category,data可以有多个.
一个Activity可以有多组intent-filter,只要intent匹配其中任何一组就可以启动该Activity.
Action的匹配规则
Action是一个字符串,系统预定义的些Action,我们可以定义自己的Action.
intent中的Action和过滤规则中的Action要完全一致,如果定义的过滤规则中有多个Action,只需要和其中一个匹配.
intent的Action必须存在,否则匹配失败.
Acyion严格区分大小写.
Category的匹配规则
Category也是一个字符串,系统预定义了一些Category,我们也可以定义自己的Category;
intent中如果含有Category,不管有多少个,每个都必须和过滤规则中的Category中的某一个相同;
intent可以没有Category,调用startActivity()或者startActivityForResult()默认会给intent加上 "android.intent.category.DEFAULT",因此,为了Activity可以被接收隐式调用,就必须加上"android.intent.category.DEFAULT"这个过滤规则;
data的匹配规则
过滤规则中定义了data,则intent中也需要定义可匹配的data;
data的语法示例:
data由mineType和URL两个部分组成,mineType表示媒体类型,例如image/jpeg,audio/mpeg4-generic,video/*等,可以表示图片文本视频等格式;
URI的格式:
<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]
具体实例:
content://com.example.project:200/folder/subfolder/etc
https://www.baidu.com:80/search/info
Scheme:URI的模式,比如file,scheme,content等,如果url没有指定scheme没有指定Scheme,则这个URI是整个无效的;
Host:URI的主机名,比如www.google.com,如果Host未指定,则整个URL中的其他参数无效;也可以说整个url无效;
Port:端口号,只有指定了Scheme和Host,端口号才有意义;
Path,pathPrefix,pathPattern:用于描述路径信息,path表示完整的路径信息,pathPrefix也表示完整的路径信息,但是它可以包含通配符"",""用于表示0或者多个字符,由于正则表达式的规范,如果是想表达真实的字符串," * "要写成"\\ * ","\"要写成"\\\\",pathPatter表示前缀信息;
data的匹配规则类似于Action,它也要求intent必须包含data,且data与过滤规则中的某个data完全匹配;
如
<intent-filter>
<data android:mineType = "image/*"/>
....
</intent-filter>
此处指定了美体类型为所有类型的图片,对应的intent中的data也必须为"image/*"
过滤规则虽然没有指定URI,但有默认值,默认值为content和file,所有intent的url的Scheme也必须是content或者是file;
为了匹配此处的规则我们可以写出如下:
intent.setDataAndType(Uri.parse("file://abc),"image/png");
为intent指定完整的data必须使用setDataAndType(),如果分别调用setData和setType,这两个方法会消除对方的值,具体可看源码;setData会把mineType设为null,setType会把URI会设置为null