Android 开发杂记(一)

324 阅读6分钟

Activity的生命周期和启动模式

典型情况下的生命周期

image.png

  1. 第一次启动:onCreate() => onStart() => onResume()

  2. 打开新的 Activity & 回到桌面:onPause() => onStop() ,当使用透明主题的时候,Activity不会走 onStop()

  3. 用户回到原先的Activity:onReStart() => onStart() => onResume()

  4. Back按钮回退:onPause() => onStop() => onDestroy()

  5. Activity 被系统回收 生命周期如 1

  6. onCreate()OnDestroy() 配对只被调用一次,onResume()onPause() 配对随着用户操作和熄亮屏操作调用多次,onStart()onStop() 同理。

onStart()onStop() 对和 onResume()onPause()的区别?

无明显区别,onStart()组跟后台相关,onResume()组针对于前台的显示相关,因为这两组生命周期直接和显示相关,不推荐在onPause()onResume()做耗时操作。

注意:ActivityA 到 ActivityB A的onPause后 B才能显示

异常情况下的生命周期

  1. 资源相关的系统配置发生改变导致Activity被重建

    这种情况比如 设备由横屏切换为竖屏,系统会应用不同情况下的图片资源,如Drawable-landscape,默认情况下系统会销毁当前的Activity并且重建Activity.

    当重建发生时,onPause(),onStop(),onDestroy()均会被执行,因为是异常情况终止,系统会调用onSaveInstanceState()来保存当前的状态,onSaveInstanceState()的调用时机在onStop()之前,与onPause()的调用没有关系,相同的被异常终止而重建的Activity会在onStart()后调用onRestoreInstanceState(),两个方法之间是由Bundle进行数据的交流,系统默认帮我们做了些处理,onSaveInstanceState()onRestoreInstanceState()默认会帮我们保存和恢复诸如滚动视图的滑动位置,输入框的已输入内容等数据.具体的细节和过程可以查看Android源码.

  2. 资源内存不足导致的低优先级Activity被杀死

    Activity的优先级排序

    1. 前台正在显示的Activity
    2. 可见的非前台的Activity,如Activity弹出个全屏Dialog
    3. 后台Activity

同样的,被杀死后通过onSaveInstanceState()onRestoreInstanceState()重建.

我想避免某些系统配置发生变化的时候重建Activity,该怎么操作呢?

可以指定Activity的android:configChanges = "" 具体的可以查询对应的参数列表,通过指定对应的场景不执行重建Activity,这时可以在Activity的onConfigurationChanged()回调中进行特殊处理.

Android的启动模式

  1. standard:标准模式

    每次使用该模式都会创建应该新的实例,该实例回执行完整的典型情况下的生命周期,该实例运行在启动它的的Activity的任务栈中.

    为什么使用applicatioContext无法使用标准模式启动Activity呢?

    因为application并没有自己的任务栈,无法存放这个新启动Activity的实例,通常回价格NEW_TASK的FLAG,实际上这步是使用SingleTask的方式启动了新的Activity,为其创建了一个新的任务栈.

  2. singleTop:栈顶复用

    如果新的Activity已经位于栈顶,则这个Activity不会被重建,但会触发onNewIntent,我们可以使用这个方法获取信息,这个Activity的onCreate()onStart()不会被重新调用,如果被启动Activity不位于栈顶,则依旧会重建.

  3. singleTask:栈内复用

    如果这个Activit不存在,会创建这个Activity的实例,系统会确认这个Activity需要任务栈存不存在,不存在则会创建一个任务栈.与singleTask类似,但只要这个Activity在栈内存在就不会重建,同样的不会重走onCreate()onStart(),可以在onNewIntent中重新获取信息,实例不存在则会压入栈中.singleTop具有clearTop效果,如1号栈有Activity ABCD,B以SingleTask的方式启动,且B需要的任务栈也为1号栈,则系统会把当前前台Activity切回B,并将CD清除掉,因此最终结果是AB.

  4. 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的语法示例:

image.png

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