【原創(chuàng)】fragment隱藏顯示方式來(lái)控制切換tab支持橫豎屏記憶回收,切換過(guò)快又使用動(dòng)畫(huà)導(dǎo)致重疊問(wèn)題解決


    static long lastClickTime = 0;

    public static Fragment switchPagesByHide(Map<Integer, PairX<String, SoftReference<Fragment>>> map, FragmentManager fragmentManager, int fragment_container_id, int key) {

        Fragment fragment;
        ArrayList<Fragment> needHideFragments = new ArrayList<>();
        for (Integer currentKey : map.keySet()) {
            if (currentKey == key) {
                continue;
            }
            PairX<String, SoftReference<Fragment>> pair = map.get(currentKey);
            fragment = pair.second.get();
            if (fragment == null) {
                fragment = fragmentManager.findFragmentByTag(getFragmentTagName(pair.first));
                if (fragment != null && fragment.isAdded()) {
                    needHideFragments.add(fragment);
                    if (BuildConfig.DEBUG && AppContext.DEBUG_) {
                        Log.w(TAG, "from tag fragment :" + fragment.getClass().getSimpleName());
                    }
                }
                continue;
            } else if (fragment.isAdded()) {
                needHideFragments.add(fragment);
            } else {
                fragment = fragmentManager.findFragmentByTag(getFragmentTagName(fragment.getClass()));
                if (fragment != null && fragment.isAdded()) {
                    needHideFragments.add(fragment);
                    if (BuildConfig.DEBUG && AppContext.DEBUG_) {
                        Log.w(TAG, " and instance not add,from tag fragment :" + fragment.getClass().getSimpleName());
                    }
                }
            }
        }
        PairX<String, SoftReference<Fragment>> pair = map.get(key);

        Fragment currentFragment = pair.second.get();
        Fragment tagCurrentFragment = fragmentManager.findFragmentByTag(getFragmentTagName(currentFragment.getClass().getName()));
        if (currentFragment == null) {
            if (tagCurrentFragment != null) {
                currentFragment = tagCurrentFragment;
            } else {
                try {
                    currentFragment = (Fragment) Class.forName(pair.first).newInstance();
                    pair.second = new SoftReference<>(currentFragment);
                } catch (Throwable e) {
                    e.printStackTrace();
                }
            }
        } else if (tagCurrentFragment != null && tagCurrentFragment.isAdded()) {//當(dāng)前如果tag里面有還是需要隱藏它.
            needHideFragments.add(tagCurrentFragment);
        }

        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        for (Fragment fragment_ : needHideFragments) {
            //if (!fragment_.isHidden()) {
            if (BuildConfig.DEBUG && AppContext.DEBUG_) {
                if (fragment_.isHidden()) {
                    Log.w(TAG, "REPEAT_HIDE_" + fragment_.getClass().getSimpleName());
                } else {

                    Log.w(TAG, "HIDE_" + fragment_.getClass().getSimpleName());
                }
            }
            fragmentTransaction.hide(fragment_);
//            popBackStackImmediate
            //}
        }
        if (!(currentFragment instanceof MyFragment) && !AppUtils.isPadBySizeLarge(AppContext.getInstance())) {//因?yàn)殡[藏了actionbar,所以會(huì)出現(xiàn)白屏,不能動(dòng)畫(huà)
            long currentMs = System.currentTimeMillis();
            if (lastClickTime == 0 || currentMs - lastClickTime > 5500) {
                currentFragment.setEnterTransition(createTransition());
                currentFragment.setReenterTransition(createTransition());
                lastClickTime = currentMs;
                if(BuildConfig.DEBUG){
                    Log.w(TAG,"_fragment anim:"+currentFragment.getClass().getSimpleName());
                }
            }else{//必須設(shè)置,否則依然會(huì)因?yàn)榍袚Q過(guò)快導(dǎo)致重復(fù).
                currentFragment.setEnterTransition(null);
                currentFragment.setReenterTransition(null);
            }

        }
        if (currentFragment.isAdded()) {
            if (BuildConfig.DEBUG) {
                Log.w(TAG, "FRAGMENT_SHOW:"+currentFragment.getClass().getSimpleName()+",before_hidden:" + currentFragment.isHidden() + ",save:" + currentFragment.isStateSaved() + ",detach:" + currentFragment.isDetached() + ",add:" + currentFragment.isAdded());
            }
            fragmentTransaction.show(currentFragment);
        } else {
            if (BuildConfig.DEBUG) {
                Log.w(TAG, "FRAGMENT_ADD:" + currentFragment.isHidden() + ",save:" + currentFragment.isStateSaved() + ",detach:" + currentFragment.isDetached() + ",add:" + currentFragment.isAdded() + "," + currentFragment);
            }
            fragmentTransaction.add(fragment_container_id == 0 ? R.id.fragment_space : fragment_container_id, currentFragment, getFragmentTagName(currentFragment.getClass()));
        }
        fragmentTransaction.commitAllowingStateLoss();

        return currentFragment;
    }

解決辦法,頻繁點(diǎn)擊就直接清除動(dòng)畫(huà),不使用動(dòng)畫(huà)

如果還是有重疊,最后經(jīng)過(guò)修改的版本是這樣的



    public static Fragment switchPagesByHide(Map<Integer, PairX<String, SoftReference<Fragment>>> map, FragmentManager fragmentManager, int fragment_container_id, int key, DialogUtils.INotify<Fragment> onHiddenNotify, DialogUtils.INotify<Fragment> onShowNotify) {
        Fragment fragment;
        ArrayList<Fragment> needHideFragments = new ArrayList<>();
        for (Integer loopKey : map.keySet()) {
            if (loopKey == key) {
                continue;
            }
            PairX<String, SoftReference<Fragment>> pair = map.get(loopKey);
            fragment = pair.second.get();
            if (fragment == null) {
                fragment = fragmentManager.findFragmentByTag(getFragmentTagName(pair.first));
                if (fragment != null) {
//                if (fragment != null && fragment.isAdded()) {
                    needHideFragments.add(fragment);
                    if (BuildConfig.DEBUG && AppContext.DEBUG_) {
                        Log.w(TAG, "from tag fragment :" + fragment.getClass().getSimpleName());
                    }
                }
                continue;
           /* } else if (!fragment.isHidden()) {
                needHideFragments.add(fragment);*/
            } else {
//                fragment = fragmentManager.findFragmentByTag(getFragmentTagName(fragment.getClass()));
//                if (fragment != null && !fragment.isHidden()) {
                needHideFragments.add(fragment);
                if (BuildConfig.DEBUG && AppContext.DEBUG_) {
                    Log.w(TAG, " and instance not add,from tag fragment :" + fragment.getClass().getSimpleName());
                }
//                }
            }
        }
        PairX<String, SoftReference<Fragment>> pair = map.get(key);
        Fragment currentFragment = pair.second.get();
        Fragment tagCurrentFragment = currentFragment == null ? null : fragmentManager.findFragmentByTag(getFragmentTagName(currentFragment.getClass().getName()));
        if (currentFragment == null) {
            if (tagCurrentFragment != null) {
                currentFragment = tagCurrentFragment;
            } else {
                try {
                    currentFragment = (Fragment) Class.forName(pair.first).newInstance();
                    pair.second = new SoftReference<>(currentFragment);
                } catch (Throwable e) {
                    e.printStackTrace();
                }
            }
        } else if (tagCurrentFragment != null && tagCurrentFragment.isAdded()) {//當(dāng)前如果tag里面有還是需要隱藏它.
            if (BuildConfig.DEBUG) {
                Log.w(TAG, "FIND REPEAT FROM TAG");
            }
        }

        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        for (Fragment fragment_ : needHideFragments) {
            //if (!fragment_.isHidden()) {
            if (BuildConfig.DEBUG && AppContext.DEBUG_) {
                if (fragment_.isHidden()) {
                    Log.w(TAG, "REPEAT_HIDE_" + fragment_.getClass().getSimpleName());
                } else {

                    Log.w(TAG, "HIDE_" + fragment_.getClass().getSimpleName());
                }
            }
            fragmentTransaction.hide(fragment_);
            if (fragment_.isResumed()) {
                onHiddenNotify.onNotify(fragment_);
            }
//            popBackStackImmediate
            //}
        }
        if (!(currentFragment instanceof MyFragment) && !AppUtils.isPadBySizeLarge(AppContext.getInstance())) {//因?yàn)殡[藏了actionbar,所以會(huì)出現(xiàn)白屏,不能動(dòng)畫(huà)
            long currentMs = System.currentTimeMillis();
      /*      if (lastClickTime == 0 || currentMs - lastClickTime > 3000) {
                currentFragment.setEnterTransition(createTransition());
                currentFragment.setReenterTransition(createTransition());
                lastClickTime = currentMs;
                if (BuildConfig.DEBUG) {
                    Log.w(TAG, "_fragment anim:" + currentFragment.getClass().getSimpleName());
                }
            } else {//必須設(shè)置,否則依然會(huì)因?yàn)榍袚Q過(guò)快導(dǎo)致重復(fù).
                currentFragment.setEnterTransition(null);
                currentFragment.setReenterTransition(null);
            }*/

        }
        if (currentFragment.isAdded()) {
            if (BuildConfig.DEBUG) {
                Log.w(TAG, "FRAGMENT_SHOW:" + currentFragment.getClass().getSimpleName() + ",before_hidden:" + currentFragment.isHidden() + ",save:" + currentFragment.isStateSaved() + ",detach:" + currentFragment.isDetached() + ",add:" + currentFragment.isAdded());
            }
//            fragmentTransaction.remove(currentFragment).commitNowAllowingStateLoss();//  Fragment no longer exists for key f#0: unique id 5893b1ef-2180-4110-ac1a-36ffc36df0b1 viewPager2.setSaveEnabled(false);
            fragmentTransaction.show(currentFragment);

            if (onShowNotify != null && currentFragment.isResumed()) {
                onShowNotify.onNotify(currentFragment);
            }
        } else {
            if (BuildConfig.DEBUG) {
                Log.w(TAG, "FRAGMENT_ADD_NEW :currentStatus:is hidden:" + currentFragment.isHidden() + ",save:" + currentFragment.isStateSaved() + ",detach:" + currentFragment.isDetached() + ",add:" + currentFragment.isAdded() + "," + currentFragment);
            }
            fragmentTransaction.add(fragment_container_id == 0 ? R.id.fragment_space : fragment_container_id, currentFragment, getFragmentTagName(currentFragment.getClass()));
            if (currentFragment.isHidden()) {
                fragmentTransaction.show(currentFragment);
            }
            if (onShowNotify != null && !currentFragment.isResumed()) {
                onShowNotify.onNotify(currentFragment);
            }
        }
        fragmentTransaction.commitAllowingStateLoss();

        return currentFragment;
    }

其實(shí)分別屏蔽了2個(gè)分支的邏輯,因?yàn)橥瑫r(shí)返回有重疊,但是概率非常低,橫豎屏方式無(wú)法測(cè)試出來(lái),快速點(diǎn)擊還是有概率出現(xiàn) ,所以改成了最終的代碼

測(cè)試回收的方法非常簡(jiǎn)單,就是不固定橫屏或者豎屏旋轉(zhuǎn)屏幕就可以讓activity重建,

在onCreate中 是先添加進(jìn)去,然后從savedInstanceState中重新找出來(lái),找到的進(jìn)行替換。這樣保證了順序問(wèn)題,


    ArrayMap<Integer, FragmentUtil.PairX<String, SoftReference<Fragment>>> fragments = new ArrayMap<>();


            fragments.put(R.id.navigation_home, pairHome);
            fragments.put(R.id.navigation_app, new FragmentUtil.PairX<String, SoftReference<Fragment>>(AppModuleNewStyleFragment.class.getName(), new SoftReference<>(new AppModuleNewStyleFragment())));
            fragments.put(R.id.navigation_reportform, new FragmentUtil.PairX<String, SoftReference<Fragment>>(ReportFormsFragment.class.getName(), new SoftReference<>(new ReportFormsFragment())));
            fragments.put(R.id.navigation_notifications, new FragmentUtil.PairX<String, SoftReference<Fragment>>(NotificationsFragment.class.getName(), new SoftReference<>(new NotificationsFragment())));
            fragments.put(R.id.navigation_my, new FragmentUtil.PairX<String, SoftReference<Fragment>>(MyFragment.class.getName(), new SoftReference<>(new MyFragment())));

        

        if (savedInstanceState != null) {
            int tab_id = savedInstanceState.getInt("tab_id");
            for (Integer key : fragments.keySet()) {
                Fragment fragment = getSupportFragmentManager().getFragment(savedInstanceState, key + "");
                if (fragment != null) {
                    fragments.put(key, new FragmentUtil.PairX<String, SoftReference<Fragment>>(fragment.getClass().getName(), new SoftReference<>(fragment)));
                    if (BuildConfig.DEBUG) {
                        Log.w(TAG, "" + fragment.getClass().getName() + "從存儲(chǔ)中恢復(fù)了");
                    }
                }
            }
            binding.navView.setSelectedItemId(tab_id);
        }

在保存狀態(tài)方法中

@Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.w(TAG, "onSaveInstanceState");
        for (Map.Entry<Integer, FragmentUtil.PairX<String, SoftReference<Fragment>>> entry : fragments.entrySet()) {
            FragmentUtil.PairX<String, SoftReference<Fragment>> pair = entry.getValue();
            if (pair.second.get() != null) {
                Fragment fragment = pair.second.get();
                if (fragment != null && fragment.isAdded()) {
                    getSupportFragmentManager().putFragment(outState, entry.getKey() + "", fragment);
                }
            } else {

            }
        }
        outState.putInt("tab_id", getBinding().navView.getSelectedItemId());
    }

PairX類(lèi)

    public static class PairX<First, Second> {
        public First first;
        public Second second;

        public PairX(First first, Second second) {
            this.first = first;
            this.second = second;
        }
    }


我這里用弱引用是為了解決被回收了,但是依然被activity持有的問(wèn)題,不然我為什么不直接用replace方法呢,replace是我以前常用的方法,然后使用強(qiáng)引用,但是這樣不會(huì)自動(dòng)回收replace之前的fragment吧。

重疊的坑很多,我順便給幾個(gè)參考鏈接
各種坑的解決
https://blog.51cto.com/u_15303287/3089390
fragment自身法隱藏解決重疊
https://blog.csdn.net/weixin_33805557/article/details/92344513
http://www.itdecent.cn/p/d9143a92ad94

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容