Android 四大组件之 Activity

读前思考
学习一门技术或者看一篇文章最好的方式就是带着问题去学习,这样才能在过程中有茅塞顿开、灯火阑珊的感觉,记忆也会更深刻。

  1. 说下 Activity 的生命周期?
  2. Activity A 启动另一个 Activity B 会回调哪些方法?如果 Activity B 是完全透明呢?如果启动的是一个 Dialog 呢?
  3. 谈谈 onSaveInstanceState() 方法?何时会调用?
  4. 如何避免配置改变时 Activity 重建?
  5. 优先级低的 Activity 在内存不足被回收后怎样做可以恢复到销毁前状态?
  6. 说下 Activity 的四种启动模式?分别会在什么时候使用?
  7. onNewIntent()调用时机?
  8. 如何启动其他应用的Activity?
Activity 生命周期
onCreate() -> onStart() - > onResume() -> onPause() -> onStop() -> onDestroy()
Android 四大组件之 Activity
文章图片

  • onCreate(): 在活动第一次被创建时会调用,可以在这个方法中完成初始化操作,如:布局加载、绑定事件等。
  • onStart(): 在活动由不可见变为可见时候调用。
  • onResume(): 在返回栈顶端,获得焦点,可以和用户进行交互。
  • onPause: 失去焦点,系统去启动另一个活动时候会调用,可以在这里做一些数据保存,资源释放,但不能做耗时操作。
  • onStop: 活动完全不可见时调用。
  • onDestroy: 活动被销毁时调用。
  • onRestart: 活动由后台不可见变为前台可见时候调用。
启动 Activity
A 启动 B 重写 A 和 B 的生命周期方法
A 启动 B
com.keven.jianshu E/TAG: A 的 onPause() com.keven.jianshu E/TAG: B 的 onCreate() com.keven.jianshu E/TAG: B 的 onStart() com.keven.jianshu E/TAG: B 的 onResume() com.keven.jianshu E/TAG: A 的 onStop()

从 B 返回 A
com.keven.jianshu E/TAG: B 的 onPause() com.keven.jianshu E/TAG: A 的 onRestart() com.keven.jianshu E/TAG: A 的 onStart() com.keven.jianshu E/TAG: A 的 onResume() com.keven.jianshu E/TAG: B 的 onStop() com.keven.jianshu E/TAG: B 的 onDestroy()

A 启动透明的 B (或者 Dialog 形式)
com.keven.jianshu E/TAG: A 的 onPause() com.keven.jianshu E/TAG: B 的 onCreate() com.keven.jianshu E/TAG: B 的 onStart() com.keven.jianshu E/TAG: B 的 onResume()

onSaveInstanceState
异常情况下的生命周期:比如当系统资源配置发生改变以及系统内存不足时,activity 就可能被杀死或者销毁后重建。
1. Activity 横竖屏切换
com.keven.jianshu E/TAG: A 的 onCreate() com.keven.jianshu E/TAG: A 的 onCreate() 中 savedInstanceState 是空的吗?true com.keven.jianshu E/TAG: A 的 onStart() com.keven.jianshu E/TAG: A 的 onResume() com.keven.jianshu E/TAG: A 的 onPause() com.keven.jianshu E/TAG: A 的 onStop() com.keven.jianshu E/TAG: A 的 onSaveInstanceState() com.keven.jianshu E/TAG: A 的 onDestroy() com.keven.jianshu E/TAG: A 的 onCreate() com.keven.jianshu E/TAG: A 的 onCreate() 中 savedInstanceState 是空的吗?false com.keven.jianshu E/TAG: A 的 onStart() com.keven.jianshu E/TAG: A 的 onRestoreInstanceState() com.keven.jianshu E/TAG: A 的 onResume()

可以看到横竖屏切换时,会调用 onSaveInstanceState( )进行状态保存,再次创建时,会调用 onRestoreInstanceState( ) 方法进行数据的恢复。
解决办法:
可以通过在清单文件中设置如下属性,避免横竖屏切换时重新创建。
android:configChanges="orientation|screenSize"

2、内存不足时 资源内存不足导致低优先级的 activity 被杀死
这里的情况和前面横竖屏切换的数据存储和恢复是完全一致的,activity 按照优先级从高到低可以分为如下三种:
  1. 前台 activity: 正在和用户交互的 activity,优先级最高
  2. 可见但非前台 activity,比如 activity 中弹出了一个对话框,导致 activity 可见但是位于后台无法和用户直接交互。
  3. 后台 activity,已经被暂停的 activity,比如执行了 onStop,优先级最低。
启动模式
standard-默认模式 这个模式是默认的启动模式,即标准模式,在不指定启动模式的前提下,系统默认使用该模式启动 Activity,每次启动一个 Activity 都会重写创建一个新的实例,不管这个实例存不存在,这种模式下,谁启动了该模式的 Activity,该 Activity 就属于启动它的 Activity 的任务栈中。
singleTop-栈顶复用模式 这个模式下,如果新的 activity 已经位于栈顶,那么这个 Activity 不会被重写创建,同时它的 onNewIntent 方法会被调用,通过此方法的参数我们可以去除当前请求的信息。如果栈顶不存在该 Activity 的实例,则情况与 standard 模式相同。需要注意的是这个 Activity 它的 onCreate(),onStart() 方法不会被调用,因为它并没有发生改变。
singleTask-栈内复用模式 在这个模式下,如果栈中存在这个 Activity 的实例就会复用这个 Activity,不管它是否位于栈顶,复用时,会将它上面的 Activity 全部出栈,并且会回调该实例的 onNewIntent 方法。其实这个过程还存在一个任务栈的匹配,因为这个模式启动时,会在自己需要的任务栈中寻找实例,这个任务栈就是通过 taskAffinity 属性指定。如果这个任务栈不存在,则会创建这个任务栈。
singleInstance-全局唯一模式 该模式具备 singleTask 模式的所有特性外,与它的区别就是,这种模式下的 Activity 会单独占用一个Task栈,具有全局唯一性,即整个系统中就这么一个实例,由于栈内复用的特性,后续的请求均不会创建新的 Activity 实例,除非这个特殊的任务栈被销毁了。以 singleInstance 模式启动的 Activity 在整个系统中是单例的,如果在启动这样的 Activiyt 时,已经存在了一个实例,那么会把它所在的任务调度到前台,重用这个实例。
隐式启动
采用隐式方式启动 Activity 时,可以用 PackageManager 的 resolveActivity 方法或者 Intent 的 resolveActivity 方法判断是否有 Activity 匹配该隐式 Intent。
IntentFilter 匹配规则:
  1. 一个 intent 只有同时匹配某个 Activity 的 intent-filter 中的 action、category、data 才算完全匹配,才能启动该 Activity。
  2. 一个 Activity 可以有多个 intent-filter,一个 intent 只要成功匹配任意一组 intent-filter,就可以启动该 Activity。
a. action 匹配规则:
要求 intent 中的 action 存在且必须和 intent-filter 中的其中一个 action 相同。 区分大小写。
b. category 匹配规则:
intent 中的 category 可以不存在,这是因为此时系统给该 Activity 默认加上了
< categoryandroid:name="android.intent.category.DEAFAULT" />

属性值。 除上述情况外,有其他 category,则要求 intent 中的 category 和 intent-filter 中的所有 category 相同。
c. data 匹配规则:
【Android 四大组件之 Activity】如果 intent-filter 中有定义 data,那么 Intent 中也必须也要定义 data。 data 主要由 mimeType (媒体类型)和 URI 组成。在匹配时通过 intent.setDataAndType(Uri data, String type) 方法对 date 进行设置。

    推荐阅读