美文网首页
Fragment采坑记录

Fragment采坑记录

作者: 人丑茶凉 | 来源:发表于2019-03-27 18:34 被阅读0次
    • 1、 bug现象:当手机上的app运行的数量 超过手机清理的上限,即内存不足时,应用进入后台再次打开时嵌套的Fragment页面显示空白; 问题分析:内存不足时,宿主Activity会被异常关闭,当再次打开时,Activity重新创建,但嵌套的Fragment填充发生了错乱。

    解决问题:复现bug,会发现除嵌套的Fragment外,其他的Fragment显示和点击事件均正常,也就是说问题可以锁定在嵌套的Fragment的宿主Fragment。 问题范围锁定后,查阅资料,发现与FragmentManager(Fragment管理类)有关。回看代码, 问题在对象FragmentTransaction,发现宿主Activity和宿主Fragment获取对象FragmentTransaction的方式均为 getSupportFragmentManager().beginTransaction(),而宿主Fragment需要使用getChildFragmentManager().beginTransaction(), 替换代码,重新运行,问题解决; 总结:Activity中获取对象FragmentTransaction,统一使用getSupportFragmentManager().beginTransaction(); Fragment中获取对象FragmentTransaction,统一使用getChildFragmentManager().beginTransaction()。

    补充(语言有些书面难懂,不求甚解者可忽略):关于getChildFragmentManager() 和 getSupportFragmentManager() getChildFragmentManager()是fragment中的方法, 返回的是管理当前fragment内部子fragments的manager. getSupportFragmentManager()在activity和fragment中都有. 在activity中, 方法用getSupportFragmentManager(), 返回的是管理activity中fragments的manager. 在fragment中, 还叫getSupportFragmentManager(), 返回的是把自己加进来的那个manager. 也即, 如果fragment在activity中, fragment.getFragmentManager()得到的是activity中管理fragments的那个manager. 如果fragment是嵌套在另一个fragment中, fragment.getFragmentManager()得到的是它的parent的getChildFragmentManager(). 总结就是: getFragmentManager()是本级别管理者, getChildFragmentManager()是下一级别管理者. 这实际上是一个树形管理结构.

    • 2、 bug现象:当手机上的app运行的数量 超过手机清理的上限,即内存不足时,应用进入后台再次打开时点击或者滑动Fragment应用闪退。

    问题分析:内存不足时,宿主Activity会被异常关闭,当再次打开时,Activity重新创建, 但与Viewpager结合使用的Fragment生命周期异常,viewpager的适配器继承自FragmentPagerAdapter,页面虽然被恢复, 但Fragment内的数据均被回收,所以Fragment会出现空指针。

    解决问题:经不断探索目前有两种解决方案。

    第一种,在Fragment集合放入适配器之前, 利用getSupportFragmentManager().getFragments(),获取到新的List<Fragment>, 然后遍历并删除这个集合内的所有的Fragment对象, 删除Fragment对象的代码:

    getSupportFragmentManager().beginTransaction().remove(saveFragmentList.get(i)).commit()。
                List<Fragment> saveFragmentList = getSupportFragmentManager().getFragments();
                for (int i = 0; i < saveFragmentList.size(); i++) {
                    getSupportFragmentManager().beginTransaction().remove(saveFragmentList.get(i)).commit();
                }
                list1Fragment = new List1Fragment();
                list2Fragment = new List2Fragment();
                list3Fragment = new List3Fragment();
                list4Fragment = new List4Fragment();
                fragmentList.clear();
                fragmentList.add(list1Fragment);
                fragmentList.add(list2Fragment);
                fragmentList.add(list3Fragment);
                fragmentList.add(list4Fragment);
    

    第二种,解释起来比较麻烦,代码比较直观,直接上代码。

    List<Fragment> saveFragmentList = getSupportFragmentManager().getFragments();
                if (saveFragmentList != null && saveFragmentList.size() > 0) {
                    list1Fragment = (List1Fragment) saveFragmentList.get(0);
                    list2Fragment = (List2Fragment) saveFragmentList.get(1);
                    list3Fragment = (List3Fragment) saveFragmentList.get(2);
                    list4Fragment = (List4Fragment) saveFragmentList.get(3);
                } else {
                    list1Fragment = new List1Fragment();
                    list2Fragment = new List2Fragment();
                    list3Fragment = new List3Fragment();
                    list4Fragment = new List4Fragment();
                }
                fragmentList.clear();
                fragmentList.add(list1Fragment);
                fragmentList.add(list2Fragment);
                fragmentList.add(list3Fragment);
                fragmentList.add(list4Fragment);
    

    个人比较倾向于第二种。这两种方法的区别是,第一种会重新绘制所有相关的Fragment, 而第二种会保存Activity异常销毁前的Fragment的展示状态。

    相关文章

      网友评论

          本文标题:Fragment采坑记录

          本文链接:https://www.haomeiwen.com/subject/ypstbqtx.html