Fragmentation onSupportInviable 不调用的问题.

**最近仔细看了一下作者提交的历史记录,最新版本(先于本文发表时间)已经解决了该问题,解决思路和本文一致"

先说解决方案吧:

修改FragmentMagiciangetActiveFragments方法,为:

 public static List<Fragment> getActiveFragments(FragmentManager fragmentManager) {
        if (!(fragmentManager instanceof FragmentManagerImpl))
            return Collections.EMPTY_LIST;
      
        return fragmentManager.getFragments();
    }

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

在项目开发中,之前一直指导fragment生命周期可见性超级复杂,项目紧,任务重,没有太多的时间来解决生命周期可见性的逻辑问题,这也是我一直不使用fagment的原因,新的项目因为需要每个页面都显示设备的状态信息,本来想用BaseActivity监听event 事件完成设备的状态监测, 然后在子activity里填充页面内容.但是总感觉不是很爽,早就关注了fragmentation这个开源库,看起来能把fragment的使用超级简化,就想着尝试用一下单activity + fragment 方案.首先不得不感谢一下作者,这个库真的是极大的简化了fragment 的使用

但是在使用过程中,也不知道是我带哦用的问题还是什么原因,出现了onSupportInvisbile 方法不调用的问题,先说一下我的项目跳转顺序

image.png

如图四个fragment顺序跳转,调用的方法是start(Fragment),我的起往是 跳转到下一个fragment 前,当前fragment 知道自己被隐层了,也就是会调用 onSupportInVisble方法,但是结果却是这样

WaitFragment}=====>onSupportVisible
WaitFragment}=====>onSupportInVisible   //注意一下只有第一个调用了 onSupportInvisible
InputCardNoFragment}=====>onSupportVisible 
BeforeTakePhotoFragment}=====>onSupportVisible
TakePhotoFragment}=====>onSupportVisible

没办法,看源码把,之前我们先注意一下,第一个也就是WaitFragment有掉onSupportInVisible方法,其他都没调

一系列的调用就不多罗嗦了,我们直接跳转到关键方法,为TransactionDelegate类的doDispatchStartTransaction(FragmentManager fm, ISupportFragment from, ISupportFragment to, int requestCode, int launchMode, int type)方法,from是调用start方法的fragmnet,to是要跳转的fragment,我把这个方法的代码跟start方法相关的代码摘了一下主要就两行

private void doDispatchStartTransaction(FragmentManager fm, ISupportFragment from, ISupportFragment to, int requestCode, int launchMode, int type) {
        checkNotNull(to, "toFragment == null");
        //获取最初的fragment
        from = getTopFragmentForStart(from, fm);
/** 一段代码表示从 当前栈顶的fragment 里拿到 containerId把toFragment填进去**/
        //开始处理start 的逻辑
        start(fm, from, to, toFragmentTag, dontAddToBackStack, sharedElementList, false, type);
    }

然后再看start的逻辑

private void start(FragmentManager fm, final ISupportFragment from, ISupportFragment to, String toFragmentTag,
                       boolean dontAddToBackStack, ArrayList<TransactionRecord.SharedElement> sharedElementList, boolean allowRootFragmentAnim, int type) {
       
        if (addMode) {
                ft.add(from.getSupportDelegate().mContainerId, toF, toFragmentTag);
                if (type != TYPE_ADD_WITHOUT_HIDE && type != TYPE_ADD_RESULT_WITHOUT_HIDE) {
//这里我们本来想hide的应该是调用start 方法的fragment,也就是上一个方法的from,但是在上一个方法中被替换成了第一个fragment,hide fragment 会调用被hide的fragment 的onSupportInVisible方法(该fragment 得是 SupportFragment的子类)
                    ft.hide(fromF);
                }
         
        supportCommit(fm, ft);
    }

大致意思就是在第二个方法中,会hide 掉from Fragment,但是在第一个方法中,传给第二个方法的from 被替换成了第一个fragment(WaitFragment),每次hide 的也都是都是第一个frgment,这样也跟我们的日志是符合的,即只有第一frgment 会调用onSupoortInVisible方法.

所以我们现在可以推测,之所以当前fragment 跳转到下一个fragment之前不能调onSupportInviaible,原因是当前fragment没有按照预想的顺序位于栈顶

这个时候我们在查看栈视图,果然发现这些fragment在栈内的顺序是乱七八糟的,很难找到规律..

那接下来就是要排查为什么当前fragment不能位于栈顶呢,我们继续查看获取栈顶frgment 的方法:getTopFragmentForStart

  private ISupportFragment getTopFragmentForStart(ISupportFragment from, FragmentManager fm) {
        ISupportFragment top;
        if (from == null) {
            top = SupportHelper.getTopFragment(fm);
        } else {
            if (from.getSupportDelegate().mContainerId == 0) {
                Fragment fromF = (Fragment) from;
                if (fromF.getTag() != null && !fromF.getTag().startsWith("android:switcher:")) {
                    throw new IllegalStateException("Can't find container, please call loadRootFragment() first!");
                }
            }
            top = SupportHelper.getTopFragment(fm, from.getSupportDelegate().mContainerId);
        }
        return top;
    }

核心代码就是
SupportHelper.getTopFragment(fm, from.getSupportDelegate().mContainerId)

再进去看这个方法:

 public static ISupportFragment getTopFragment(FragmentManager fragmentManager, int containerId) {
        List<Fragment> fragmentList = FragmentationMagician.getActiveFragments(fragmentManager);
        if (fragmentList == null) return null;

        for (int i = fragmentList.size() - 1; i >= 0; i--) {
            Fragment fragment = fragmentList.get(i);
            if (fragment instanceof ISupportFragment) {
                ISupportFragment iFragment = (ISupportFragment) fragment;
                if (containerId == 0) return iFragment;

                if (containerId == iFragment.getSupportDelegate().mContainerId) {
                    return iFragment;
                }
            }
        }
        return null;
    }

意思大致就是从FragmentationMagician.getActiveFragments(fragmentManager)中获取到最末尾的装在containerId中的 SupportFragment,本例四个fragment 全中.

再看getActiveFragments 的源码:

 if (!(fragmentManager instanceof FragmentManagerImpl))
            return Collections.EMPTY_LIST;
        // For pre-25.4.0
        if (sSupportLessThan25dot4) return fragmentManager.getFragments();

        // For compat 25.4.0+
        try {
            FragmentManagerImpl fragmentManagerImpl = (FragmentManagerImpl) fragmentManager;
            // Since v4-25.4.0,mActive: ArrayList -> SparseArray
            return getActiveList(fragmentManagerImpl.mActive);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return fragmentManager.getFragments();

support 版本0超过25.4.0,会走return getActiveList(fragmentManagerImpl.mActive);这个方法,

private static List<Fragment> getActiveList(HashMap<String, Fragment> active) {
        if (active == null) {
            return Collections.EMPTY_LIST;
        }
        final int count = active.size();
        ArrayList<Fragment> fragments = new ArrayList<>(count);
        fragments.addAll(active.values());
        return fragments;
    }

意思就是将参数的值封装到list中,之前调用时传入的参数是fragmentManagerImpl.mActive 点进去一看,阿西吧!!!原来是个HashMap,这顺序怎么保证!!!自然也就乱套了..但是令人感到奇怪的是,点返回键出栈的顺序居然和我们设想的一样,也没再研究作者是怎么做到的.

final ArrayList<Fragment> mAdded = new ArrayList<>();
final HashMap<String, Fragment> mActive = new HashMap<>();

至于这个mActive 和mAdd的fragment 的区别,我看了半天也没搞明白,但是至少madded 是有顺序的,暂时先返回这个吧...有什么隐患以后再说把..于是修改FragmentMagiciangetActiveFragments方法,强行返回那个有顺序的list:

 public static List<Fragment> getActiveFragments(FragmentManager fragmentManager) {
        if (!(fragmentManager instanceof FragmentManagerImpl))
            return Collections.EMPTY_LIST;
      
        return fragmentManager.getFragments();
    }

调整后的日志,符合预期,看栈的顺序也符合预期了..出栈正常,有什么其他问题,暂时还没有测试,目前满足这种简单的但是需要可见性检测的场景

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