前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >咱真的了解 Activity 与 Fragment 生命周期吗?

咱真的了解 Activity 与 Fragment 生命周期吗?

作者头像
阿策小和尚
发布2019-08-12 16:06:50
1.3K0
发布2019-08-12 16:06:50
举报
文章被收录于专栏:阿策小和尚阿策小和尚

和尚我中午和朋友闲聊,被问到 Activity 与 Fragment 的生命周期,以为是很基础的东西,基本可以把生命周期说全,但是被问到 Activity 与 Fragment 交互的生命周期运行顺序,切换 Fragment 时候的生命周期顺序,以及切换完之后退出时的生命周期…瞬间感觉基础知识太不扎实了。 不禁问一下和尚自己:我真的了解 Fragment 的生命周期么?


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


Activty 与 Fragment 生命周期执行顺序

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

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

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

Activity 与 Fragment 生命周期流程图

Fragment 切换(replace 方式)

  1. 初始化 Activity 与 FragmentAK,之后切换初始化 FragmentBK 生命周期执行顺序:
  1. 应用切换至后台的执行顺序:
  1. 应用切换至前台的执行顺序:
  1. 由 FragmentBK 切换回 FragmentAK 生命周期执行顺序:
  1. 最终展示 FragmentBK 时销毁 Activity 与 (一个) Fragment 生命周期执行顺序:

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

主要代码:(Kotlin 方式)

代码语言:javascript
复制
// 初始化加载 Fragment
fun initData() {
    if (fragmentA == null) {
        fragmentA = FragmentAK()
    }
    supportFragmentManager.beginTransaction().replace(R.id.fl_content, fragmentA).commitAllowingStateLoss()
    tv_toolbar_title.text = "FragmentAK"
    fragment = fragmentA
}
// 点击切换 Fragment
fun 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 生命周期执行顺序:
  1. 应用切换至后台的执行顺序:
  1. 应用切换至前台的执行顺序:
  1. 销毁 Activity 与 (三个) Fragment 生命周期执行顺序:

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

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

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

主要代码:(Kotlin 方式)

代码语言:javascript
复制
// 初始化加载 Fragment
fun 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
}
// 点击切换 Fragment
fun 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


和尚真正认识到基础知识太重要了,得努力学扎实些啊!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-04-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 阿策小和尚 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Activty 与 Fragment 生命周期执行顺序
  • Fragment 切换(replace 方式)
  • Fragment 切换(hide/show 方式)
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档