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

      小菜中午和朋友闲聊,被问到 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 方式)

// 初始化加载 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 生命周期执行顺序:


    初始化三个 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 方式)

// 初始化加载 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

      小菜真正认识到基础知识太重要了,得努力学扎实些啊!下面的是小菜我的公众号,欢迎闲来吐槽哦~
小菜公众号
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345