记一次Fragment引起的血案

Fragment引起的血案

前几天遇到一个很奇怪的问题,主页Fragment的onResume中的接口,存在偶现的频繁刷接口的现象。
看上去代码一切正常,我们也重现不出来,但是线上就是存在刷接口的现象,被我们运维频频吐槽。
在百思不得其解之际,终于找到突破口 : 自己对于Fragment的使用一直存在误区。

Fragment的使用误区

Fragment在Activity旋转屏幕或重建后,并不会销毁,而是存储在saveInstanceState中。
先附上我们平时对于Fragment的用法,( 这是错误的 )
如果Activity发生了重建,这会导致内存中,存在两份Fragment,
甚至于,该Activity多次重建后,就会有多个Fragment同时存在,
而这些Fragment都会重新走生命周期,导致生命周期中的接口被多次频繁调用。

getSupportFragmentManager().beginTransaction()
                .add(R.id.layout_container, SecondFragment.newInstance(), "SecondFragment")
                .commit();
方案一

Fragment的show和add方法应该结合使用,如果能够找到对应的tag的fragment,应该要show Fragment,而不是新创建一个fragment来add

正确用法:

Fragment fragment = getSupportFragmentManager().findFragmentByTag("SecondFragment");
if (fragment != null) {
    getSupportFragmentManager().beginTransaction()
            .show(fragment)
            .commit();
}else{
    getSupportFragmentManager().beginTransaction()
            .add(R.id.layout_container, SecondFragment.newInstance(), "SecondFragment")
            .commit();
}
方案二

在所有fragment的使用中,都判断show和add,相对比较繁琐,如果对于fragment重用没有要求,那么我们完全可以禁止fragment的缓存,从而一劳永逸,解决这个问题。

在Activity的onSaveInstanceState,加入如下代码

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    // 只要发生onSaveInstanceState就remove all Fragment
    if (outState != null) {
        Log.i(TAG, "outState.remove");
        outState.remove("android:support:fragments");
    }
}
方案三

如果我们对大厂的App们进行测试,会发现一个惊人的秘密,大厂的App完全禁止了App的SaveInstanceState,即不用再考虑App销毁重建时,数据的存储恢复情况,这不仅仅可以避免fragment的问题,还可以避免因遗漏对某些数据进行存储/恢复处理,导致的异常情况的发生。
当然这也有代价,那就是系统回收了App后,无法保存现场页面状态和数据。

@Override
public void onSaveInstanceState(Bundle outState) {
	//注释掉这行
    //super.onSaveInstanceState(outState);
}

为什么我们的Activity会发生重建

我们的app的旋转方向限定为竖屏,理论上不会发生Activity重建的情况。
那是什么场景导致Activity重建呢 ? 搜寻资料后发现

在 Android 的 API 21 ( Android 5.0 ) 以下,Crash 会直接退出应用,但是在 API 21 ( Android 5.0 ) 以上,系统会遵循以下原则进行重启:

  • 包含 Service,如果应用 Crash 的时候,运行着Service,那么系统会重新启动 Service。
  • 不包含 Service,只有一个 Activity,那么系统不会重新启动该 Activity。
  • 不包含 Service,但当前堆栈中存在两个 Activity:Act1 -> Act2,如果 Act2 发生了 Crash ,那么系统会重启 Act1。
  • 不包含 Service,但是当前堆栈中存在三个 Activity:Act1 -> Act2 -> Act3,如果 Act3 崩溃,那么系统会重启 Act2,并且 Act1 依然存在,即可以从重启的 Act2 回到 Act1。

国内有些厂商可能会去除这个功能

所以,我们有时候出现崩溃,会发现App并没有闪退,而是会恢复到上一个页面 (上一个页面进行了重建)。

小结

至此,我们知道了Fragment的使用中,add/show的误区,并给出了解决方案。
并说明了Activity重建的情况,扩展了自己的认知边界。
在日后的工作中,我们应该要避免Fragment错误使用的情况。

最后,附上用来重现该问题的Demo

相关资料

Android 解决应用崩溃后重启的问题
解决Fragment中调用getActivity()为null的多种方法

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

氦客

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值