Activity 和 Fragment 生命周期

2022-06-02  本文已影响0人  沐风雨木

生命周期,就是一个对象从创建到销毁的过程,每一个对象都有自己的生命周期。同样,Activity 也具有相应的生命周期,在 Activity 的生命周期中分为四种状态,分别是运行状态、暂停状态、停止状态和销毁状态。
Activity 从一种状态转变到另一种状态时会触发一些事件,执行一些回调方法来通知状态的变化,在这里 Activity 类提供了六个核心回调:onCreate()、onStart()、onResume()、onPause()、onStop()onDestroy()。当 Activity 进入新状态时,系统会调用其中每个回调。

一. Activity 运行状态

1. 基本状态

值得一提的是,当 Activity 处于运行状态时,Android 会尽可能地保持它的运行,
即使出现内存不足的情况,Android 也会先杀死栈底部的 Activity,来确保可见的 Activity 正常运行。

2. 状态转换

当一个 Activity 实例被创建、销毁或者启动另外一个 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
  1. Activity 第一次启动,回调如下:onCreate -> onStart -> onResume
Activity 第一次启动
  1. 打开新 Activity 或按 Home 键:onPause->onStop
打开新 Activity 或按 Home 键
  1. 再次回到 Activity:onRestart->onStart->onResume
再次回到 Activity
  1. 如果新的 ActivityThemeDialog 或者 Translucent(透明)时不会调用 onStop 方法。
新的 Activity 的 Theme 为 Dialog 或者 Translucent
  1. Back 键退出 ActivityonPause->onStop->onDestroy
按 Back 键退出 Activity
注:一般这里只会走 onPause() 和 onStop(),当把 app 杀死时,才会调用 onDestrroy()。
(2)ActivityA 启动 ActivityB

正常情况下:

ActivityA 启动 ActivityB

返回 ActivityA:

返回 ActivityA
(3)Theme 为 Dialog 或 Translucent

ActivityA 启动 ActivityC:

ActivityA 启动 ActivityC

返回 ActivityA:

返回 ActivityA
(4)旋转屏幕横竖屏切换(未指定 configChanges)

Activity 正常运行,此时旋转屏幕:

旋转屏幕

当系统配置被更改时 Activity会被销毁并重新创建,ActivityonPause、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 方法在 onStartonResume 之间调用用以恢复 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 优先级

当系统内存不足时会按照上面的优先级进行销毁,并通过 onSaveInstanceState()onRestoreInstanceState() 来存储与恢复数据。

防止 Activity 被重新创建
当某项内容被改变时不想停止并重新创建 Activity 可以通过在 AndroidManifest 清单文件中对该 Activity 指定 configChanges 属性来防止重新创建:

比如旋转屏幕时不想重新创建 Activity 可以指定 orientation 这个属性值,
如:android:configChanges="orientation",
如果想指定多个值可以用 “|” 来连接起来如:
android:configChanges="orientation|keyboardHidden"

一些 configChanges 属性:

configChanges 属性

在指定 configChanges 之后 Activity 在该系统配置改变的情况下不会重新创建 Activity 也不会调用 onSaveInstanceState()onRestoreInstanceState() 来保存或恢复数据,取而代之的是使用 onConfigurationChanged() 方法。

    @Override
    public void onConfigurationChanged(@NonNull Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Log.d("ActivityA 生命周期", "onConfigurationChanged()");
    }

三. Activity 四种启动模式

四. OnNewIntent()

Activity 被设以 singleTop 模式启动,当需要再次响应此 Activity 启动需求时,会复用栈顶的已有 Activity,还会调用 onNewIntent()。并且,再接受新发送来的 intent(onNewIntent()) 之前,一定会先执行 onPause(),如下图所示:

生命周期

1. onNewIntent() 与启动模式

前提: ActivityA 已经启动过,处于当前应用的 Activity 任务栈中; 
(1)当 ActivityA 的 LaunchMode 为 standard 时:

由于每次启动 ActivityA 都是启动新的实例,和原来启动的没关系,所以不会调用原来 ActivityAonNewIntent()

(2)当 ActivityA 的 LaunchMode 为 SingleTop 时:

如果 ActivityA 在栈顶,且现在要再启动 ActivityA,这时会调用onNewIntent() ,生命周期顺序为:

LaunchMode 为 SingleTop
(3)当 ActivityA 的 LaunchMode 为 singleInstance,singleTask:

如果 ActivityA 已经在任务栈中,再次启动 ActivityA,那么此时会调用 onNewIntent(),生命周期调用顺序为:

LaunchMode 为 singleInstance,singleTask

因此:onNewIntent() 在情况 1 不调用,在情况 23 调用。

更准确的说法是,只对 singleTop(且位于栈顶),singleTasksingleInstance(且已经在任务栈中存在实例)的情况下,再次启动它们时才会调用,即只对 startActivity 有效,对仅仅从后台切换到前台而不再次启动的情形,不会触发 onNewIntent()

五. Fragment 生命周期

FragmentAndroid v3.0 版本开始引入的,随着界面布局的复杂化,处理起来也更加的复杂,引入 Fragment 可以把 Activity 拆分成多个部分。一个 Activity 可以同时组合多个 Fragment,一个 Fragment 也可被多个 Activity 复用。Fragment 可以响应自己的输入事件,并拥有自己的生命周期,但它们的生命周期直接被其所属的 Activity 的生命周期控制。

1. Fragment 状态

Fragment 状态与 Activity 类似,也存在如下 4 种状态:

2. 生命周期状态

Fragment 的生命周期与 Activity 的生命周期十分相似,如下图所示:

Activity 和 Fragment 生命周期对比流程图
可以看到 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

创建 Fragment

(2)按下 Home 键回到桌面 / 锁屏

按下 Home 键回到桌面 / 锁屏

(3)从桌面回到 Fragment / 解锁

从桌面回到 Fragment / 解锁

(4)按下 Back 键退出

按下 Back 键退出

Activity 和 Fragment 生命周期调用

打开页面 按下主屏幕键 重新打开

Fragment 生命周期与 Activity 生命周期的一个关键区别就在于,Fragment 的生命周期方法是由托管 Activity 而不是操作系统调用的。Activity 中生命周期方法都是 protected,而 Fragment 都是 public,也能印证了这一点,因为 Activity 需要调用 Fragment 那些方法并管理它。

Fragment 和 Fragment 生命周期调用
FragmentA 切换到 FragmentB 时变化:

(1)通过 add hide show 方式来切换

当以这种方式进行 FragmentA 与 FragmentB 的切换时,
Fragment 隐藏的时候并不走 onDestroyView,
所有的显示也不会走 onCreateView 方法,所有的 view 都会保存在内存。

(2)使用 replace 的方法进行切换时

注:通过 replace 方法进行替换的时,Fragment 都是进行了销毁,
重建的过程,相当于走了一整套的生命周期

(3)使用 ViewPager 进行切换时
当使用 ViewPagerFragment 进行切换时,Fragment 会进行预加载操作。

切回去也是一样的。

上一篇 下一篇

猜你喜欢

热点阅读