1.1Activity生命周期全面分析

activity lifecycle

  • onCreate(), 加载界面布局资源,初始化Activity需要的数据等
  • onStart(), Activity已经是可见状态,但未出现在前台,无法与用户交互;
  • onResume(), Activity已经可见,处于前台,所以一般如果需要返回页面自动刷新数据时,将请求的方法放在onResume;
  • onPause(), 不能做太耗时的操作,onPause必须执行完,新的Activity才会启动,也就是说ActivityA跳转到ActivityB,执行顺序: ……A:onPause()->B:onCreate()->B:onStart()->B:onResume()->A:onStop()
  • onStop(), Activity不可见时会调用,所以当新的Activity采用透明主题时,当前Activity不会调用onStop();
  • onDestroy(), 回收资源,取消注册广播等;

onStart()和onStop()是从Activity是否可见来回调,而onResume()和onPause()是从Activity是否位于前台来回调。

异常情况下的生命周期,有两种:
1.资源相关的系统配置发生改变导致Activity被杀死并重新创建
如locale, 设备本地位置发生变化(一般指切换了系统语言);keyboardHidden,键盘可访问性发生改变;orientation,屏幕方向发生改变;等
2.系统内存不足导致优先级低的Activity被杀死
优先级由高到低: 前台Activity > 可见但非前台Activity > 后台Activity
异常情况下系统会调用onSaveInstanceState保存当前Activity的状态(调用时机在onStop之前,但具体是onPause前后不确定),Activity被销毁后重启会将保存的Bundle对象同时传递给onRestoreInstanceState和onCreate方法(不过建议在onRestoreInstanceState做恢复数据操作)

1.2 Activity的四种启动模式

1.standard, 标准模式。Activity默认会进入启动它的Activity所在的任务栈中
2.singleTop, 栈顶复用模式。若新Activity已经位于任务栈栈顶,那么该Activity不会被重建,并且会调用onNewIntent方法(onCreate和onStart不会被调用),若不是栈顶,Activity则会重建;
3.singleTask, 栈内复用模式。只要Activity在它需要的任务栈中存在,那么多次启动该Activity都不会重新创建实例(不在栈顶的会清除它上面的Activity以达到栈顶,即CLEAR_TOP功能),和singleTop一样,系统会回调onNewIntent. 如:

a.当前任务栈S1为ABC,D以singleTask启动,需要任务栈为S2(不存在),则系统会创建S2, 然后创建D,并压入S2;
b.若D需要的是栈S1,则会创建D,然后入栈到S1;
c.若栈S1为ADBC,D需要栈S1,因为S1已经有D的实例,所以BC会出栈,变为AD;

4.singleInstance, 单实例模式。加强版的singleTask, 拥有singleTask的所以特性,只能单独位于一个任务栈中,一旦创建后,除非任务栈被系统销毁,不然就不会重新创建新的Activity

注:
a.TaskAffinity是标识singleTask所需要的任务栈的参数,一般任务栈名为应用包名,所以TaskAffinity不能和应用包名一样。另外,任务栈分为前台和后台任务栈,后台的Activity处于暂停状态,可以切换调到前台。

b.TaskAffinity和allowTaskReparenting=true结合时,比较特殊,会发生任务栈转移,如应用A启动了应用B的ActivityC(allowTaskReparenting=true), 当home键后再启动应用B时会进入ActivityC(任务栈有A到B)

c.启动方式: 代码优先级高于manifast配置的优先级

d.Activity的Flag
1).FLAG_ACTIVITY_NEW_TASK对应singleTask
2).FLAG_ACTIVITY_SINGLE_TOP对应singleTop
3).FLAG_ACTIVITY_CLEAR_TOP同一栈内位于它上面的Activity全部出栈,一般配合FLAG_ACTIVITY_NEW_TASK使用
4).FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS不会出现在Activity历史列表,等同于android:excludeFromRecents=”true”
FLAG方式不能设置singleInstance模式

1.3IntentFilter的匹配规则

启动Activity方式有两种: 显式调用和隐式调用,显式调用要明确被启动的对象的包名类名,隐式调用则不需要,但要设置过滤规则。IntentFilter的过滤信息有: action, category, data。一个Activity可以有多个intent-filter, 一个Intent只要匹配一组intent-filter(必须同时匹配action、category和data)就可以成功启动Activity

  • action的匹配规则
    只要Intent中的action和过滤规则中的任何一个action相同即可匹配成功,action匹配区分大小写。
  • category匹配规则
    Intent中如果有category,则所有的category都必须和过滤规则中的其中一个category相同,如果没有category的话那么就是默认的category, 即android.intent.category.DEFAULT, 所以为了Activity能够接收隐式调用,配置多个category的时候必须加上默认的category。
  • data匹配规则
    Intent中必须有data数据,并且data数据能够完全匹配过滤规则中的某一个data
    data语法如下:
    1
    2
    3
    4
    5
    6
    7
    <data android:scheme="string"
    android:host="string"
    android:port="string"
    android:path="string"
    android:pathPattern="string"
    android:pathPrefix="string"
    android:mimeType="string" />

data主要由mineType和URI两部分组成。mineType是媒体类型,如image/jpeg, video/等,URI结构如下:
<scheme>://<host>:<port>/[<path>]|[<pathPrefix>]|[pathPattern]
例如content://com.example.project:200/folder/subfolder/etc
scheme、host、port分别表示URI的模式、主机名和端口号,其中如果scheme或者host未指定那么URI就无效。 path、pathPattern、pathPrefix
都是表示路径信息,其中path表示完整的路径信息,pathPrefix表示路径的前缀信息;pathPattern表示完整的路径,但是它里面包含了通配符(*
)

注:
如果过滤规则中的mimeType指定为image/* 或者text/*等这种类型的话,那么即使过滤规则中没有指定URI,URI有默认的scheme是content和file;
当为Intent指定完整的data,必须要调用setDataAndType方法!不能先调用setData然后调用setType,因为这两个方法会彼此清除对方的值。应使用:

1
intent.setDataAndType(Uri.parse("file://abc"), "image/png");

判断是否有Activity能够匹配我们的隐式Intent的两种方法:
1.用PackageManager的resolveActivity方法或者Intent的resolveActivity方法:如果找不到就会返回null;
2.用PackageManager的queryIntentActivities方法: 它返回所有成功匹配的Activity信息 针对Service和BroadcastReceiver等组件,PackageManager同样提供了类似的方法去获取成功匹配的组件信息,例如queryIntentServices、queryBroadcastReceivers等方法。
有一类action和category比较重要,它们在一起用来标明这是一个入口Activity,并且会出现在系统的应用列表中。

1
2
3
4
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

<完>