文章

Fragment坑

Fragment坑

Fragment 常见坑

Fragment 踩过的坑

内存重启: app 运行在后台的时候,系统资源紧张的时候导致把 app 的资源全部回收(杀死 app 的进程),这时把 app 再从后台返回到前台的时候,app 会重启;回收之前,系统会把 Activity 的状态保存下来,Activity 的 FragmentManager 负责把 Activity 的 Fragment 保存起来。在内存重启后,Activity 的恢复是从栈顶逐步恢复,Fragment 会在宿主 Activity 的 onCreate () 方法调用后紧接着恢复 (从 onAttach () 生命周期开始)

1、getActivity () 空指针

原因:调用了 getActivity () 时,当前的 Fragment 已经 onDetach () 了宿主 Activity。

1
2
3
4
5
6
7
@Override
public void onAttach(Context context) {
    super.onAttach(context);

    mContext = context;
    //        mContext = getActivity();
}
  1. 切换 Fragment 的时候,会频繁的被 crash
  2. 系统内存不足
  3. 横竖屏幕切换的时候

以上情况都会导致 Activity 被系统回收,但是由于 fragment 的生命周期不会随着 Actiivty 被回收而被回收,因此才会导致 getActivity () 出现 null 的问题

解决:

  1. 利用 getApplicationContext ()
  2. Fragment 生命周期
    在 Fragment 的生命周期中,在生命周期处于 onAttach () 和 onDetach () 之间的时候 getActivity () 方法才不会返回 null。

2、Fragment 重叠异常 —– 正确使用 hide、show 的姿势

见下面的 Fragment重影

3、Fragment 嵌套的那些坑

4、不靠谱的出栈方法 remove ()

5、多个 Fragment 同时出栈的那些深坑 BUG

6、超级深坑 Fragment 转场动画

Fragment 内存重启

其实就是在 Activity 重新创建 onCreate 的时候,会将 args 重新赋值给 Fragment,所以通过 setArguments 传递的会保留

后台 app,导致 getActivity () 为空

Fragment 之 java. lang. IllegalStateException  Can not perform this action after onSaveInstanceState

IllegalStateException: Can not perform this action after onSaveInstanceState:
#解决办法 :onSaveInstanceState 方法是在该 Activity 即将被销毁前调用,来保存 Activity 数据的,如果在保存玩状态后
再给它添加 Fragment 就会出错。解决办法就是把 commit()方法替换成 commitAllowingStateLoss ()

https://bugly.qq.com/v2/crash-reporting/crashes/d33adba520/495?pid=1

Fragment 重影之 add、hide、show

现象

假设底部有 3 个 tab: tab 1, tab 2, tab 3, 对应的引用分别为 Fragment 1 Fg、Fragment 2 Fg、Fragment 3 Fg;通过 FragmentManager 进行 add/show/hide 操作;切换到 tab 1, 此时 tab 1 = new Fragment 1 Fg (), 即 tab 1 变量指向 new Fragment 1 Fg ();这个时候, 按下 Home 长时间后台导致内存不足, 系统回收了 tab 1 的引用变成 tab 1 = null;而 tab 1 的实例还是存在内存中的,只是引用被销毁了,这时候切换到 tab 2,隐藏 tab 1,显示 tab 2,而 tab 1 已经为 null,无法实现 hide 操作,而由于 tab 1 的 Fragment 实例还在内存中,就会导致 tab 2 和 tab 1 重叠现象,再切换到 tab 1,由于 tab 1 为 null 会再次创建 tab 1 = new Fragment 1 Fg (),此时会再去创建一个新的 Fragment,放到 tab 1 上,导致原来的 tab 1 上的 Fragment 实例一直存在与内存中导致重影,置为被垃圾回收机回收

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Fragment1fg f1;
Fragment2fg f2;
private void f11() {
    FragmentTransaction transaction = manager.beginTransaction();
    f1 = new Fragment1fg();
    if (!f1.isAdded()) {
        transaction.add(R.id.framelayout, f1);
    }
    if (f2 != null && f2.isAdded()) {
        transaction.hide(f2);
    }
    transaction.commit();
}
private void f22() {
    FragmentTransaction transaction = manager.beginTransaction();
    f2 = new Fragment2fg();
    if (!f2.isAdded()) {
        transaction.add(R.id.framelayout, f2);
    }
    if (f1 != null && f1.isAdded()) {
        transaction.hide(f1);
    }
    transaction.commit();
}
  • 模拟:开发者选项,不保留活动
  • 重影现象:
  • 解决通过 tag 解决
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
Fragment f1;
Fragment f2;
private void f11() {
    FragmentTransaction transaction = manager.beginTransaction();
    f1 = manager.findFragmentByTag("f1");
    f2 = manager.findFragmentByTag("f2");
    if (f1 == null) {
        this.f1 = new Fragment1fg();
    }
    if (!f1.isAdded()) {
        transaction.add(R.id.framelayout, this.f1, "f1");
    } else {
        transaction.show(f1);
    }
    if (f2 != null && f2.isAdded()) {
        transaction.hide(f2);
    }
    transaction.commit();
}
private void f22() {
    FragmentTransaction transaction = manager.beginTransaction();
    f1 = manager.findFragmentByTag("f1");
    f2 = manager.findFragmentByTag("f2");
    if (f2 == null) {
        f2 = new Fragment2fg();
    }
    if (!f2.isAdded()) {
        transaction.add(R.id.framelayout, f2, "f2");
    } else {
        transaction.show(f2);
    }
    if (f1 != null && f1.isAdded()) {
        transaction.hide(f1);
    }
    transaction.commit();
}
  • 再次验证:

Ref

  1. Fragment全解析系列(一):那些年踩过的坑
  2. Fragment 全解析系列(二):正确的使用姿势
  3. Fragment 之我的解决方案:Fragmentation
本文由作者按照 CC BY 4.0 进行授权