Activity 常见问题总结

Activity 的生命周期

Activity 生命周期

生命周期方法

  • onCreate
    首次建立 Activity 时调用,应该在这里执行必须的初始化工做,例如 setContentView、加载数据、绑定 View 等。
  • onStart
    在 Activity 即将对用户可见以前调用,这里能够作一些 UI 相关的初始化操做,也能够注册 Receiver、开始监听 Bus 事件等。
  • onResume
    在 Activity 即将开始与用户进行交互以前调用。此时 Activity 处于栈顶并接收全部的用户输入,能够在这里初始化相机、开始播放视频等。
  • onPause
    在 Activity 失去焦点时会被调用,此时依然可见,但颇有可能会紧接 onStop 而后退出 Activity。此时能够作一些存储数据、中止动画、释放相机之类的工做,但不能太耗时,由于只有当它完成后,新的 Activity 才能继续执行。
  • onStop
    在 Activity 对用户不可见时调用,例如 Activity 退出或被其它 Activity 覆盖,一样这里能够保存数据、作一些稍微重量级的回收工做。
  • onDestroy
    在 Activity 被销毁前调用。当 Activity 结束(调用 finish 方法),或系统为节省空间销毁此 Activity 时会被调用,能够经过 isFinishing 方法区分这两种状况。全部未释放的资源要在这里回收,不须要继续执行的异步操做要中止,防止内存泄漏。
  • onRestart
    在 Activity 从彻底不可见状态从新回到前台时调用。

生命周期方法中,有三对是相互对应的,即 onCreate 与 onDestroy、onStart 与 onStop、onPause 与 onResume。一些初始化工做例如初始化相机、初始化播放器、开始播放、注册 Receiver、监听 GPS 坐标变化、监听 Bus 事件等,在哪里开始并无必定之规,应当根据具体的业务须要在 onCreate / onStart / onResume 中选择最合适的,但必定要在其相对应的生命周期方法中执行相反的操做或者释放资源,才能保证在各类状态都不会出现问题。html

典型场景

与上述生命周期方法相对应,Activity 有这些状态: Created / Started / Resumed / Paused / Stopped / Destroyed 。其中 Created / Started 是瞬间状态,由于调用 onCreate 以后马上会调用 onStart,而 onStart 以后也必定会当即调用 onResume。Resumed / Paused / Stopped 是持久状态,例如 Activity 在前台且得到焦点,此时是 Resumed 状态;可见但未得到焦点,例如被一个 dialog 样式的 Activity 覆盖、多窗口模式下其它窗口得到了焦点,此时就是 Paused 状态;而 Activity 被彻底覆盖且未销毁的状况之下,会一直停留在 Stopped 状态。android

单个 Activity 的流程

进入:onCreate -> onStart -> onResume
按 Home 键或者被新的 Activity 彻底覆盖:onPause -> onStop
退出:onPause -> onStop -> onDestroy数据库

多个 Activity 协做的流程

Activity A 启动了 Activity B(B 不是 dialog 样式):
A.onPause -> B.onCreate -> B.onStart -> B.onResume -> A.onStop
从 Activity B 再退回 Activity A:
B.onPause -> A.onRestart -> A.onStart -> A.onResume -> B.onStop -> B.onDestroy网络

异常状况下的生命周期

系统配置发生变化

系统配置发生变化时,Activity 会被销毁并重建,由于 Android 系统中的资源都是和系统配置相关的,例如咱们的 layout 可能取决于设备是横屏仍是竖屏,String 取决于当前系统语言等,重建 Activity 会根据新的系统配置加载合适的资源。
销毁时 Activity 的 onPause、onStop、onDestroy 方法会依次被调用,同时系统会调用 onSaveInstanceState 方法保存当前 Activity 的状态到 Bundle 对象中;重建时系统会调用 onRestoreInstanceState 方法并将以前保存的 Bundle 对象传递给 onCreate 方法和 onRestoreInstanceState 方法。app

系统内存不足

当系统内存不足时,低优先级的 Activity 会被系统杀死,优先级顺序从高到低以下:异步

  1. 前台 Activity:正在和用户交互的 Activity,即 Resumed 状态的 Activity。
  2. 可见 Activity:可见但不能和用户交互的 Activity,即 Paused 状态的 Activity。
  3. 后台 Activity:已经被暂停的 Activity,即 Stopped 状态的 Activity。

当系统内存不足时,会按照由低到高的优先级顺序去杀掉目标 Activity 所在进程,并在后续经过 onSaveInstanceState 和 onRestoreInstanceState 来存储和恢复数据。没有运行四大组件的进程优先级最低,很容易被系统杀死,所以后台工做不该当脱离四大组件单独运行,能够放到 Service 中。ide

onSaveInstanceState 和 onRestoreInstanceState

Android P 以前 onSaveInstanceState 方法会在 onStop 以前被调用,有可能在 onPause 以前也有可能在 onPause 以后;Android P 及以后的的版本中 onSaveInstanceState 方法会在 onStop 以后被调用。
onRestoreInstanceState 方法会在 onStart 方法以后调用,其传入的 Bundle 对象必定不是 null,恢复的工做也能够放到 onCreate 方法中。 onSaveInstanceState 方法和 onRestoreInstanceState 方法的默认实现会保存和恢复当前界面中全部 View 的状态,不须要作特殊处理。
onSaveInstanceState 方法会在 Activity 须要销毁重建,或者被切换到后台时被调用,例如切换横竖屏、锁屏、被新的 Activity 彻底遮住、按 Home 键等。但这两个方法不必定是成对的被调用的,onRestoreInstanceState 被调用的前提是,Activity 确实被系统销毁了而且在重建,大部分状况下调用 onSaveInstanceState 并不意味着 Activity 真的会被销毁,只是为了保险而已。动画

常见问题

onPause 和 onStop 有什么区别?

这是个很古老的问题。两者最明显的区别是是否可见,若是 Activity 失去焦点就会调用 onPause,但只有 Activity 彻底不可见时才会调用 onStop。只调用 onPause 不调用 onStop 情景能够举下面两个例子:ui

  • 当前 Activity 被另外一个 dialog 样式的 Activity 覆盖,此时不可与用户交互但仍然可见。
  • 多窗口模式下两个 App 并列显示,但焦点被另外一个 App 抢走。

应该在 onPause 仍是 onStop 中保存数据?

这个问题有些麻烦,Android 官方文档实际上是存在自相矛盾的,咱们来分析一下:
Understand the Activity Lifecycle 中有这样一段话:this

onPause() execution is very brief, and does not necessarily afford enough time to perform save operations. For this reason, you should not use onPause() to save application or user data, make network calls, or execute database transactions; such work may not complete before the method completes. Instead, you should perform heavy-load shutdown operations during onStop().

大意是讲,onPause 方法应该快速结束,不该该在其中进行耗时操做,例如保存用户数据、发起网络请求、执行数据库事物等,这些重量级的工做应该放到 onStop 当中。
然而 Activity 类的文档中又有相反的说法:

onPause() is where you deal with the user pausing active interaction with the activity. Any changes made by the user should at this point be committed (usually to the ContentProvider holding the data). In this state the activity is still visible on screen. Note the "Killable" column in the above table -- for those methods that are marked as being killable, after that method returns the process hosting the activity may be killed by the system at any time without another line of its code being executed. Because of this, you should use the onPause() method to write any persistent data (such as user edits) to storage.

就是说 Activity 在执行完 onPause 方法后会进入”Killable“状态,系统有可能在不执行 onStop 的状况下直接杀掉进程,若是没有在 onPause 中保存数据,就没有机会了。然而 Android 3.0 以后有了细微的变化,系统能够保证杀掉进程时 onStop 也会被调用:

Be aware that these semantics will change slightly between applications targeting platforms starting with Build.VERSION_CODES.HONEYCOMB vs. those targeting prior platforms. Starting with Honeycomb, an application is not in the killable state until its onStop() has returned. This impacts when onSaveInstanceState(android.os.Bundle) may be called (it may be safely called after onPause()) and allows an application to safely wait until onStop() to save persistent state.

综合上面的观点,若是不考虑兼容 3.0 以前的系统(市面已经不多了),在 onPause 或者 onStop 中保存数据其实均可以的,都可以获得保证。可是 onPause 方法不适合执行太耗时的操做,由于不管是开启新的 Activity 仍是退出当前 Activity,都要等到 onPause 方法执行完成后才会看到新的界面,应当尽可能为其减轻负担,因此除非必定要在 onPause 中完成的部分,保存数据应当放到 onStop 中。
固然这不是彻底绝对的,也要结合具体业务需求。举个例子,好比有两个 Activity A 和 B,用户能够在 A 中设置参数,而且这个设置项要保存到 Preference 中,而 B 须要从 Preference 中读取这个设置项并显示出来。若是 A 在 onStop 方法中保存数据,当用户从 A 启动 B 时就会出问题:因为 A 的 onStop 方法调用其实在 B 初始化以后,此时 B 是没法获取到这个最新值的,这种状况 A 只能在 onPause 方法中保存数据。
另外,在 Activity 文档中 Saving Persistent State 这一节,官方建议使用“edit in place”的方式来保存数据,这种策略和 AndroidStudio 保存文件的策略类似,即数据发生改变后要随时保存,这样哪怕发生了 Crash 或者手机断电之类的极端状况,也能够保证数据不会丢失,比在 onPause 或者 onStop 中保存数据要更靠谱。

onSaveInstanceState 和 onPause、onStop 等有什么区别和联系?

onSaveInstanceState 和 onRestoreInstanceState 并非 Activity 的生命周期方法,咱们在上面那张生命周期流程图中也没有看到它们。onPause 和 onStop 是 Activity 中止或退出时会调用的方法,所以咱们通常会在其中作保存数据的操做,也就是将数据持久化到磁盘。onSaveInstanceState 方法只有系统须要重建 Activity 时,例如退到后台、系统设置发生变化、系统内存不足杀掉 Activity 时才会被调用,若是是正常的 finish 流程则不会被调用。onSaveInstanceState 虽然也是保存数据,但它的目标并非将数据持久化,而是将一些和 UI、当前状态相关的变量等交给系统来保存,若是这个 Activity 还须要再恢复,就能够用这些数据还原现场。
总结一下,调用场景不一样,调用的目的也不一样,因此说它们并无什么必然的联系。

Activity 的启动模式 - launchMode

standard(默认)

标准启动模式,每一个 Intent 从新生成一个实例。

singleTop

复用栈顶模式,若是已有相同 Activity 实例且位于栈顶,则不会从新生成实例,只会调用栈顶 Activity 的 onNewIntent() 方法;若是已有相同 Activity 且不在栈顶,仍是会生成新实例,同 standard 模式。

singleTask

首先根据指定的 taskAffinity 查找任务,若是存在就在已有任务中启动,不然启动新的任务;若是在已有任务中启动,会在任务中查找当前 Activity 的实例,找到就将其上面的全部 Activity 结束并调用该实例的 onNewIntent() 方法,不然建立新的实例。

singleInstance

单独占用一个任务,再次启动时复用已有任务和实例。该 Activity 启动的 Activity 会运行在其它任务中,和 singleTask 状况相似。

参考资料

Understand the Activity Lifecycle  |  Android Developers
Activity  |  Android Developers
任务和返回栈  |  Android Developers
《Android 开发艺术探索》第1章
Android中Activity四种启动模式和taskAffinity属性详解 - 张纪刚的博客 - CSDN博客
解开Android应用程序组件Activity的"singleTask"之谜 - 老罗的Android之旅 - CSDN博客

相关文章
相关标签/搜索