生命周期,就是一个对象从创建到销毁的过程,每一个对象都有自己的生命周期。同样,
Activity
也具有相应的生命周期,在Activity
的生命周期中分为四种状态,分别是运行状态、暂停状态、停止状态和销毁状态。
而Activity
从一种状态转变到另一种状态时会触发一些事件,执行一些回调方法来通知状态的变化,在这里Activity
类提供了六个核心回调:onCreate()、onStart()、onResume()、onPause()、onStop()
和onDestroy()
。当Activity
进入新状态时,系统会调用其中每个回调。
一. Activity 运行状态
1. 基本状态
- 运行状态(Running)当
Activity
在屏幕的最前端时,它是可见的、有焦点的。能够实现用户交互,如点击、双击、长按事件等。 - 暂停状态(Paused) 失去焦点因此不可与用户进行交互,但与窗口管理器保持连接状态,状态性和成员变量依然存在。例如,当最上面的
Activity
没有完全覆盖屏幕或者是透明的,被覆盖的Activity
仍然对用户可见,并且存活(它保留着所有的状态和成员信息并保持与Activity
管理器的连接)。但当内存不足时,这个暂停状态的Activity
可能会被杀死。 - 停止状态(Stopped) 当
Activity
完全不可见时,它就处于停止状态,但仍然保留着当前状态和成员信息。只是不可见的,但当系统内存不足时,这个Activity
很容易被杀死。 - 销毁状态(Killed)界面被系统回收后,处于销毁状态,当该界面需要再次显示与用户交互时,需要重新开始并重置。
值得一提的是,当 Activity 处于运行状态时,Android 会尽可能地保持它的运行,
即使出现内存不足的情况,Android 也会先杀死栈底部的 Activity,来确保可见的 Activity 正常运行。
2. 状态转换
当一个 Activity
实例被创建、销毁或者启动另外一个 Activity
时,它在这四种状态之间进行转换,这种转换的发生依赖于用户程序的动作。下图说明了 Activity
在不同状态间转换的时机和条件:
二. Activity生命周期
从图中可以看出,当
Activity
从启动到关闭时,会依次执行
onCreate() → onStart() → onResume() → onPause() → onStop() → onDestroy()
当 Activity
执行到 onPause()
方法失去焦点时,重新调用回到前台会执行 onResume()
方法,如果此时进程被杀死 Activity
重新执行时会先执行 onCreate()
方法。当执行到 onStop()
方法 Activity
不可见时,再次回到前台会执行 onRestart()
方法,如果此时进程被杀死 Activity
会重新执行 onCreate()
方法。
1. 常用生命周期
方法名 | 简介 |
---|---|
onCreate | 表示 Activity 正在被创建,这也是 Activity 的生命周期的第一个方法。 |
onRestart | 表示 Activity 正在重新启动,此生命周期只有在 onPause 与onStop 都执行过才会被调用 |
onStart | 表示 Activity 正在被启动,即将开始,此时 Activity 已经可见但是还没有出现在前台,还无法交互 |
onResume | 表示 Activity 已经可见并出现在前台可以与用户进行交互 |
onPause | 表示 Activity 正在停止 |
onStop | 表示 Activity 停止并不可见 |
onDestroy | 表示 Activity 即将被销毁,这是 Activity 的最后一个回调 |
2. Activity 生命周期切换过程
(1)单 Activity
-
Activity
第一次启动,回调如下:onCreate -> onStart -> onResume
。
- 打开新
Activity
或按Home
键:onPause->onStop
。
- 再次回到 Activity:
onRestart->onStart->onResume
。
- 如果新的
Activity
的Theme
为Dialog
或者Translucent
(透明)时不会调用onStop
方法。
- 按
Back
键退出Activity
:onPause->onStop->onDestroy
。
注:一般这里只会走 onPause() 和 onStop(),当把 app 杀死时,才会调用 onDestrroy()。
(2)ActivityA 启动 ActivityB
正常情况下:
返回 ActivityA:
(3)Theme 为 Dialog 或 Translucent
ActivityA 启动 ActivityC:
返回 ActivityA:
(4)旋转屏幕横竖屏切换(未指定 configChanges)
Activity 正常运行,此时旋转屏幕:
当系统配置被更改时 Activity
会被销毁并重新创建,Activity
的 onPause、onStop、onDestroy
均会被调用,同时由于 Activity
是异常情况下终止并销毁的系统会调用 onSaveInstanceState
方法来保存当前 Activity
的状态。
**注意**:当用户显式关闭 Activity 时,或者在其他情况下调用 `finish()` 时,
系统不会调用 onSaveInstanceState()。
也就是说,系统在“未经你许可”销毁 Activity 时调用 onSaveInstanceState 方法,用于保存 Activity 状态信息。
什么时候调用 onSaveInstanceState 方法:
(1) 当用户按下 HOME 键时。
(2) 切换到其他进程时。
(3) 锁屏时。
(4) 启动新的 Activity 时。
(5) 屏幕方向切换时。
什么时候调用 onRestoreInstanceState 方法:
在 Activity 被系统销毁,又回到该 Activity 的时候。如用户按下 HOME 键又马上返回该 Activity,
这个时候该 Activity 一般不会因为内存不足而被系统回收,故不调用 onRestoreInstanceState 方法。
所以 onSaveInstanceState 与 onRestoreInstanceState 不一定会成对被调用。
之后就是正常的启动流程,当然会有 onRestoreInstancesState
方法在 onStart
与 onResume
之间调用用以恢复 onSaveInstanceState
保存的状态。
onSaveInstancesState
调用时期从 Build.VERSION_CODES.P
开始在 onStop
方法之后调用;对于面向较早平台版本的应用程序,此方法将在onStop()
之前发生,链接。
接下来用 onSaveInstance()
与 onRestoreInstanceState()
来保存与恢复数据
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d("ActivityA 生命周期", "onCreate()");
if (savedInstanceState != null) {
Log.d("ActivityA 生命周期", "from onContext:" + savedInstanceState.getString("text"));
}
}
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("text","数据");
Log.d("ActivityA 生命周期", "onSaveInstanceState()");
Log.d("ActivityA 生命周期", "数据已保存:"+"数据");
}
@Override
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.d("ActivityA 生命周期", "onRestoreInstanceState()");
Log.d("ActivityA 生命周期", "from onRestoreInstancesState() 的值为:" + savedInstanceState.getString("text"));
}
我们可以在 onCreate()
和 onRestoreInstanceState()
方法进行数据的恢复处理,onCreate()
中有一个参数,此参数就是 onSaveInstanceState()
保存的值,在 onCreate()
中需要对该参数进行空判断因为此参数在 onCreate()
正常启动的情况下是为 null
的,至于 onRestoreInstanceState()
这个方法不用进行空值判断因为此方法只要被调用它的值不可能为空,代码效果如下。
(5)资源内存不足导致低优先级 Activity 被杀死
Activity 优先级
- 前台
Activity
用户正在交互的Activity
,优先级最高; - 可见但非前台
Activity
; - 后台
Activity
已经被停止的Activity
,例如执行了onStop
方法,优先级最低。
当系统内存不足时会按照上面的优先级进行销毁,并通过 onSaveInstanceState()
和 onRestoreInstanceState()
来存储与恢复数据。
防止 Activity 被重新创建
当某项内容被改变时不想停止并重新创建 Activity
可以通过在 AndroidManifest
清单文件中对该 Activity
指定 configChanges
属性来防止重新创建:
比如旋转屏幕时不想重新创建 Activity 可以指定 orientation 这个属性值,
如:android:configChanges="orientation",
如果想指定多个值可以用 “|” 来连接起来如:
android:configChanges="orientation|keyboardHidden"
一些 configChanges
属性:
在指定 configChanges
之后 Activity
在该系统配置改变的情况下不会重新创建 Activity
也不会调用 onSaveInstanceState()
或 onRestoreInstanceState()
来保存或恢复数据,取而代之的是使用 onConfigurationChanged()
方法。
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Log.d("ActivityA 生命周期", "onConfigurationChanged()");
}
三. Activity 四种启动模式
standard 模式:
standard
模式是Android
的默认启动模式,你不在配置文件中作任何设置,那么这个Activity
就是standard
模式,这种模式下,Activity
能够有多个实例,每次启动Activity
,不管任务栈中是否已经有这个Activity
的实例,系统都会建立一个新的Activity
实例。SingleTop 模式:
SingleTop
模式和standard
模式很是类似,主要区别就是当一个SingleTop
模式的Activity
已经位于任务栈的栈顶,再去启动它时,不会再建立新的实例,若是不位于栈顶,就会建立新的实例。singleTask模式:
singleTask
模式的Activity
在同一个Task
内只有一个实例,若是Activity
已经位于栈顶,系统不会建立新的Activity
实例,和singleTop
模式同样。但Activity
已经存在但不位于栈顶时,系统就会把该Activity
移到栈顶,并把它上面的Activity
出栈。singleInstance 模式:
singleInstance
模式也是单例的,但和singleTask
不一样,singleTask
只是任务栈内单例,系统里是能够有多个singleTask Activity
实例的,而singleInstance Activity
在整个系统里只有一个实例,启动singleInstance Activity
时,系统会建立一个新的任务栈,而且这个任务栈只有他一个Activity
。
四. OnNewIntent()
当 Activity
被设以 singleTop
模式启动,当需要再次响应此 Activity
启动需求时,会复用栈顶的已有 Activity
,还会调用 onNewIntent()
。并且,再接受新发送来的 intent(onNewIntent())
之前,一定会先执行 onPause()
,如下图所示:
1. onNewIntent() 与启动模式
前提: ActivityA 已经启动过,处于当前应用的 Activity 任务栈中;
(1)当 ActivityA 的 LaunchMode 为 standard 时:
由于每次启动 ActivityA
都是启动新的实例,和原来启动的没关系,所以不会调用原来 ActivityA
的 onNewIntent()
。
(2)当 ActivityA 的 LaunchMode 为 SingleTop 时:
如果 ActivityA
在栈顶,且现在要再启动 ActivityA
,这时会调用onNewIntent()
,生命周期顺序为:
(3)当 ActivityA 的 LaunchMode 为 singleInstance,singleTask:
如果 ActivityA
已经在任务栈中,再次启动 ActivityA
,那么此时会调用 onNewIntent()
,生命周期调用顺序为:
因此:onNewIntent()
在情况 1
不调用,在情况 2
和 3
调用。
更准确的说法是,只对 singleTop
(且位于栈顶),singleTask
和 singleInstance
(且已经在任务栈中存在实例)的情况下,再次启动它们时才会调用,即只对 startActivity
有效,对仅仅从后台切换到前台而不再次启动的情形,不会触发 onNewIntent()
。
五. Fragment 生命周期
Fragment
从Android v3.0
版本开始引入的,随着界面布局的复杂化,处理起来也更加的复杂,引入Fragment
可以把Activity
拆分成多个部分。一个Activity
可以同时组合多个Fragment
,一个Fragment
也可被多个Activity
复用。Fragment
可以响应自己的输入事件,并拥有自己的生命周期,但它们的生命周期直接被其所属的Activity
的生命周期控制。
1. Fragment 状态
Fragment
状态与 Activity
类似,也存在如下 4
种状态:
- 运行:当前
Fmgment
位于前台,用户可见,可以获得焦点。 - 暂停:其他
Activity
位于前台,该Fragment
依然可见,只是不能获得焦点。 - 停止:该
Fragment
不可见,失去焦点。 - 销毁:该
Fragment
被完全删除,或该Fragment
所在的Activity
被结束。
2. 生命周期状态
Fragment
的生命周期与 Activity
的生命周期十分相似,如下图所示:
可以看到
Fragment
的生命周期和 Activity
很相似,只是多了一下几个方法:onAttach(),onCreateView(),onActivityCreated(),onDestroyView()
和 onDetach()
。
再来看一下它的常用生命周期:
方法名 | 简介 |
---|---|
onAttach() | 当 Fragment 与 Activity 发生关联时调用。 |
onCreate() | 创建 Fragment 时被回调。 |
onCreateView() | 每次创建、绘制该 Fragment 的 View 组件时回调该方法,Fragment 将会显示该方法返回的 View 组件。 |
onActivityCreated() | 当 Fragment 所在的 Activity 被启动完成后回调该方法。 |
onStart() | 启动 Fragment 时被回调,此时 Fragment 可见。 |
onResume() | 恢复 Fragment 时被回调,获取焦点时回调。 |
onPause() | 暂停 Fragment 时被回调,失去焦点时回调。 |
onStop() | 停止 Fragment 时被回调,Fragment 不可见时回调。 |
onDestroyView() | 销毁与 Fragment 有关的视图,但未与 Activity 解除绑定。 |
onDestroy() | 销毁 Fragment 时被回调。 |
onDetach() | 与 onAttach() 相对应,当 Fragment 与 Activity关联被取消时调用。 |
3. 生命周期调用
Fragment 生命周期调用
(1)创建 Fragment
(2)按下 Home
键回到桌面 / 锁屏
(3)从桌面回到 Fragment
/ 解锁
(4)按下 Back 键退出
Activity 和 Fragment 生命周期调用
- 打开页面
- 按下主屏幕键
- 重新打开页面
-
按后退键
Fragment
生命周期与 Activity
生命周期的一个关键区别就在于,Fragment
的生命周期方法是由托管 Activity
而不是操作系统调用的。Activity
中生命周期方法都是 protected
,而 Fragment
都是 public
,也能印证了这一点,因为 Activity
需要调用 Fragment
那些方法并管理它。
Fragment 和 Fragment 生命周期调用
FragmentA
切换到 FragmentB
时变化:
(1)通过 add hide show
方式来切换
- FragmentA 的生命周期变化为:
回调onHiddenChanged()
方法; - FragmentB 的生命周期变化为:
onCreate() --> onCreateView() --> onActivityCreated() --> onStart() --> onResume()
; - FragmentB 再次返回到 FragmentA:
不走任何生命周期方法但是回调onHiddenChanged()
方法
当以这种方式进行 FragmentA 与 FragmentB 的切换时,
Fragment 隐藏的时候并不走 onDestroyView,
所有的显示也不会走 onCreateView 方法,所有的 view 都会保存在内存。
(2)使用 replace
的方法进行切换时
载入FragmentA 时:
FragmentA
的生命周期:onCreate() --> onCreateView() --> onActivityCreated() --> onStart() --> onResume()
-
切换到FragmentB 时:
FragmentA
的生命周期:onPause() --> onStop() --> onDestroyView() --> onDestroy() --> onDetach()
FragmentB
的生命周期:onCreate() --> onCreateView() --> onActivityCreated() --> onStart() --> onResume()
如下图:
FragmentB 切换回 FragmentA 时:
FragmentB
的生命周期:onPause() --> onStop() --> onDestroyView() --> onDestroy() --> onDetach()
FragmentA
的生命周期:onCreate() --> onCreateView() --> onActivityCreated() --> onStart() --> onResume()
注:通过 replace 方法进行替换的时,Fragment 都是进行了销毁,
重建的过程,相当于走了一整套的生命周期
(3)使用 ViewPager
进行切换时
当使用 ViewPager
与 Fragment
进行切换时,Fragment
会进行预加载操作。
- 所有的 Fragment 都会提前初始--->预加载;
- 初始化时 Fragment 们的生命周期:
FragmentA
的生命周期:onCreate() --> onCreateView() --> onActivityCreated() --> onStart() --> onResume()
FragmentB
的生命周期:同上
- FragmentA 切换到 FragmentB 的生命周期:
FragmentA
:走setUserVisVleHint()
方法;
FragmentB
:同上
。
切回去也是一样的。