博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
我们真的了解 Activity 与 Fragment 的生命周期吗?
阅读量:7295 次
发布时间:2019-06-30

本文共 4885 字,大约阅读时间需要 16 分钟。

      小菜中午和朋友闲聊,被问到 Activity 与 Fragment 的生命周期,以为是很基础的东西,基本可以把生命周期说全,但是被问到 Activity 与 Fragment 交互的生命周期运行顺序,切换 Fragment 时候的生命周期顺序,以及切换完之后退出时的生命周期...瞬间感觉基础知识太不扎实了。

      不禁问一下小菜自己:我真的了解 Fragment 的生命周期么?


      网上对于 Activity 与 Fragment 生命周期的图表很多很详细,单独的 Activity 和 Fragment 生命周期暂不说明,下面主要研究一下两个生命周期一起时的运行周期顺序以及 Fragment 切换时的生命周期顺序


Activty 与 Fragment 生命周期执行顺序

      基本的在 Activity 中添加 Fragment 的代码就不上了,小菜觉得直接上日志来的更清楚:

  1. 初始化 Activity 与 (一个) Fragment 生命周期执行顺序:
    Activity 与 Fragment 初始化
  2. 应用切换至后台的执行顺序:
    切换后台
  3. 应用切换至前台的执行顺序:
    切回前台
  4. 销毁 Activity 与 (一个) Fragment 生命周期执行顺序:
    销毁 Fragment 与 Activity

      总结一下,其实时很容易理解的,Fragment 是依赖与 Activity 的,创建时优先执行 Activity 生命周期,销毁时优先执行 Fragment 生命周期。小菜自己画了一个小流程图,虽然很不专业,但流程基本正确。(青绿色代表 Fragment 单独生命周期,蓝色代表 Activity 单独生命周期,红色代表两者交互时生命周期)

Activity + Fragment 生命周期流程图

Fragment 切换(replace 方式)

  1. 初始化 Activity 与 FragmentAK,之后切换初始化 FragmentBK 生命周期执行顺序:

    初始化两个 Fragment
  2. 应用切换至后台的执行顺序:

    切换后台
  3. 应用切换至前台的执行顺序:

    切回前台
  4. 由 FragmentBK 切换回 FragmentAK 生命周期执行顺序:

    Fragment 之间切换
  5. 最终展示 FragmentBK 时销毁 Activity 与 (一个) Fragment 生命周期执行顺序:

    销毁 Fragment 与 Activity

      小菜个人理解,replace 方式切换 Fragment 时,每次执行 replace 方式就会销毁上一个已存在的 Fragment,即 Activity 中只包含一个 Fragment。

主要代码:(Kotlin 方式)

// 初始化加载 Fragmentfun initData() {    if (fragmentA == null) {        fragmentA = FragmentAK()    }    supportFragmentManager.beginTransaction().replace(R.id.fl_content, fragmentA).commitAllowingStateLoss()    tv_toolbar_title.text = "FragmentAK"    fragment = fragmentA}// 点击切换 Fragmentfun clickFragmentLay(position: Int) {    when (position) {        0 -> {            if (fragmentA == null) {                fragmentA = FragmentAK()            }            supportFragmentManager.beginTransaction().replace(R.id.fl_content, fragmentA).commitAllowingStateLoss()            tv_toolbar_title.text = "FragmentAK"            Toast.makeText(this@TestActivityK, "切换为 FragmentAK", Toast.LENGTH_SHORT).show()        }        1 -> {            if (fragmentB == null) {                fragmentB = FragmentBK()            }            supportFragmentManager.beginTransaction().replace(R.id.fl_content, fragmentB).commitAllowingStateLoss()            tv_toolbar_title.text = "FragmentBK"            Toast.makeText(this@TestActivityK, "切换为 FragmentBK", Toast.LENGTH_SHORT).show()        }    }}

Fragment 切换(hide/show 方式)

  1. 初始化 Activity 与 FragmentAK,之后切换初始化 FragmentBK,之后再切换初始化 FragmentCK 生命周期执行顺序:

    初始化三个 Fragment
  2. 应用切换至后台的执行顺序:

    切换后台
  3. 应用切换至前台的执行顺序:

    切回前台
  4. 销毁 Activity 与 (三个) Fragment 生命周期执行顺序:

    销毁三个 Fragment 与 Activity

      如果以此方式在 Activity 中只加载两个 Fragment,简化如下:

  1. 初始化 Activity 与 (两个) Fragment,并切换至后台:

    两个 Fragment 初始化与切换
  2. 切换回前台,之后销毁 Activity 与 (两个) Fragment 生命周期执行顺序:

    两个 Fragment 销毁

      小菜个人理解,hide/show 方式切换 Fragment 时,Fragment 不销毁,其生命周期按照这几个 Fragment 的初始化顺序执行,初始化几个就执行几个 Fragment 的生命周期。

主要代码:(Kotlin 方式)

// 初始化加载 Fragmentfun initData() {    if (fragmentA == null) {        fragmentA = FragmentAK()    }    if (!fragmentA!!.isAdded()) {        supportFragmentManager.beginTransaction().add(R.id.fl_content, fragmentA).commitAllowingStateLoss()    } else {        supportFragmentManager.beginTransaction().show(fragmentA).commitAllowingStateLoss()    }    tv_toolbar_title.text = "FragmentAK"    fragment = fragmentA}// 点击切换 Fragmentfun clickFragmentLay(position: Int) {    when (position) {        0 -> {            if (fragmentA == null) {                fragmentA = FragmentAK()            }            addOrShowFragment(supportFragmentManager.beginTransaction(), fragmentA!!)            tv_toolbar_title.text = "FragmentAK"            Toast.makeText(this@TestActivityK, "切换为 FragmentAK", Toast.LENGTH_SHORT).show()        }        1 -> {            if (fragmentB == null) {                fragmentB = FragmentBK()            }            addOrShowFragment(supportFragmentManager.beginTransaction(), fragmentB!!)            tv_toolbar_title.text = "FragmentBK"            Toast.makeText(this@TestActivityK, "切换为 FragmentBK", Toast.LENGTH_SHORT).show()        }        2 -> {            if (fragmentC == null) {                fragmentC = FragmentCK()            }            addOrShowFragment(supportFragmentManager.beginTransaction(), fragmentC!!)            tv_toolbar_title.text = "FragmentCK"            Toast.makeText(this@TestActivityK, "切换为 FragmentCK", Toast.LENGTH_SHORT).show()        }    }}// addOrShowFragment 方法fun addOrShowFragment(transaction: FragmentTransaction, frag: Fragment) {    if (fragment === frag) {        return    }    if (!frag.isAdded) { // 如果当前fragment未被添加,则添加到Fragment管理器中        transaction.hide(fragment).add(R.id.fl_content, frag).commitAllowingStateLoss()    } else {        transaction.hide(fragment).show(frag).commitAllowingStateLoss()    }    fragment = frag as Fragment}

      小菜日常应用加载和切换 Fragment 的方式就这两种,应用较多的还是 hide/show 方式,因为如果在 Fragment 中执行异步线程时,若未执行完 replace 方式直接销毁会报异常,以及 getActivity() 方式会报空指针。当然如果加载很多 Fragment 时不止用到 hide/show 方式,还要涉及 Fragment 的懒加载等。

效果图 FragmentAK
效果图 FragmentBK
效果图 FragmentCK

      小菜真正认识到基础知识太重要了,得努力学扎实些啊!下面的是小菜我的公众号,欢迎闲来吐槽哦~
小菜公众号

转载地址:http://bdwnm.baihongyu.com/

你可能感兴趣的文章
[二十一]JavaIO之BufferedReader 与 BufferedWriter
查看>>
SpringCloud学习系列之三----- 断路器(Hystrix)和断路器监控(Dashboard)
查看>>
C# 使用 wkhtmltopdf 把HTML文本或文件转换为PDF
查看>>
POJ 4007 Flood-it!
查看>>
下载Crypto,CyCrypto,PyCryptodome 报错问题
查看>>
shell的奇淫巧技--自动化脚本(sed命令)
查看>>
批量更改文件名
查看>>
Hadoop1.x代码求海量数据最大值
查看>>
activemq 搭建--集群
查看>>
【洛谷4719】 动态dp(树链剖分,dp,矩阵乘法)
查看>>
运维与自动化系列③自动化部署基础与shell脚本实现
查看>>
利用window.performance.timing进行性能分析
查看>>
Java面向对象之继承
查看>>
状态模式
查看>>
ScheduledExecutorService 定时器用法
查看>>
Xshell 配置上传下载命令 rz sz 以及配置复制和粘贴
查看>>
<转载> pycharm快捷键及一些常用设置
查看>>
jmeter全链路压测
查看>>
显示逻辑卷信息
查看>>
Algs4-1.4.21无重复值之中的二分查找
查看>>