美文网首页
Activity 和 Fragment 生命周期

Activity 和 Fragment 生命周期

作者: 沐风雨木 | 来源:发表于2022-06-02 14:55 被阅读0次

    生命周期,就是一个对象从创建到销毁的过程,每一个对象都有自己的生命周期。同样,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 生命周期
    从图中可以看出,当 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 优先级

    • 前台 Activity 用户正在交互的 Activity,优先级最高;
    • 可见但非前台 Activity
    • 后台 Activity 已经被停止的 Activity,例如执行了 onStop 方法,优先级最低。

    当系统内存不足时会按照上面的优先级进行销毁,并通过 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 四种启动模式

    • 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 都是启动新的实例,和原来启动的没关系,所以不会调用原来 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 种状态:

    • 运行:当前 Fmgment 位于前台,用户可见,可以获得焦点。
    • 暂停:其他 Activity 位于前台,该 Fragment 依然可见,只是不能获得焦点。
    • 停止:该 Fragment 不可见,失去焦点。
    • 销毁:该 Fragment 被完全删除,或该 Fragment 所在的 Activity 被结束。

    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 的生命周期变化为:
      回调 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 时
    • FragmentB 切换回 FragmentA 时:
      FragmentB 的生命周期:onPause() --> onStop() --> onDestroyView() --> onDestroy() --> onDetach()
      FragmentA 的生命周期:onCreate() --> onCreateView() --> onActivityCreated() --> onStart() --> onResume()

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

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

    • 所有的 Fragment 都会提前初始--->预加载;
    • 初始化时 Fragment 们的生命周期:
      FragmentA 的生命周期:onCreate() --> onCreateView() --> onActivityCreated() --> onStart() --> onResume()
      FragmentB 的生命周期:同上
    • FragmentA 切换到 FragmentB 的生命周期:
      FragmentA :走 setUserVisVleHint() 方法;
      FragmentB同上

    切回去也是一样的。

    相关文章

      网友评论

          本文标题:Activity 和 Fragment 生命周期

          本文链接:https://www.haomeiwen.com/subject/ubjtmrtx.html