1. 程式人生 > >徹底解決Fragment重疊的問題

徹底解決Fragment重疊的問題

在佈局應用一級頁面時很多App都會採取BottomBar + Fragment切換來構建。一般Fragment會使用FragmentManager管理,就是在一個FrameLayout構成的ContentView上做show和hide,

在這裡有一個問題需要注意,在這種有多個按鈕處於一個螢幕可以快速切換Fragment的UI佈局下,不要使用add和replace去切換fragment,使用show和hide去切換是最好的選擇,因為show和hide本質上是在控制Fragment中View的Visiblity,而執行replace則會觸發fragment的detach()函式與Activity解除關聯,如果此時使用者快速點選,在detach還沒執行完就執行attach(),很容易產生IllegalStateException:no host;應用直接崩潰。

使用show和hide很容易出現的問題就是承載Fragmen的Activity在旋轉螢幕,資源不足被釋放資源然後恢復重建這些情況下,被承載的Fragment在恢復時沒能正確恢復狀態,然後全部都顯示了出來。解決這個問題的核心就是在Fragment恢復時全部隱藏,然後根據當前顯示的Fragment的TAG顯示Fragment。

本來想把這段程式碼封裝成一個Activity基類,後面想想應用一級的需求頁面千奇百怪,封裝了也沒什麼通用性,就在這裡記錄一下,分享一下順便備忘了=。=

上程式碼:

public abstract class MainActivity extends BaseActivity {

    private static final String SAVED_CURRENT_ID = "currentId";

    public static final List<String> PAGE_TAGS = new ArrayList<>();
    private List<Class<? extends BaseFragment>> fragmentClasses = Arrays.asList(HomeFragment.class,
            MoreFragment.class, ProfileFragment.class); //自定義的Fragment,主要目的是在初始化時能夠通過迴圈初始化,與重建時的恢復統一
    private List<Fragment> fragments = new ArrayList<>();

    private FragmentManager mFragmentManager;

    private int currentId = 0;

    @Override
    public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
        super.onCreate(savedInstanceState, persistentState);
        setContentView(R.layout.activity_main);
        initFragments();
    }

    private void initFragments(Bundle savedInstanceState) {
        mFragmentManager = getSupportFragmentManager();
        for(int i = 0; i < fragments.size(); i++) {
            fragments.set(i, mFragmentManager.findFragmentByTag(PAGE_TAGS.get(i)));
            if(fragments.get(i) == null) {
                try {
                    fragments.set(i,fragmentClasses.get(i).newInstance());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            //先重置所有fragment的狀態為隱藏,徹底解決重疊問題
            if(fragments.get(i).isAdded()) {
                mFragmentManager.beginTransaction()
                        .hide(fragments.get(i))
                        .commitAllowingStateLoss();
            }
        }
        if(savedInstanceState != null) {
            int cachedId = savedInstanceState.getInt(SAVED_CURRENT_ID, 0);
            if(cachedId >= 0 && cachedId <= 4) {
                currentId = cachedId;
            }
        }
        switchFragment(currentId, false);
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt(SAVED_CURRENT_ID, currentId);
    }

    private void switchFragment(int index) {
        switchFragment(index, true);
    }

    private void switchFragment(int index, boolean anim) {
        /* Fragment 切換 */
        FragmentTransaction transaction = mFragmentManager.beginTransaction();
        if(anim) {  //顯示切換動畫
            if(index > currentId) {
                transaction.setCustomAnimations(R.anim.slide_right_in, R.anim.slide_left_out);
            }
            else {
                transaction.setCustomAnimations(R.anim.slide_left_in, R.anim.slide_right_out);
            }
        }
        if(fragments.get(index).isAdded()) {
            transaction.hide(fragments.get(currentId));
            transaction.show(fragments.get(index));
        }
        else {
            transaction.hide(fragments.get(currentId));
            transaction.add(getFragmentContainerLayoutRes(), fragments.get(index), PAGE_TAGS.get(index));
            transaction.show(fragments.get(index));
        }
        transaction.setTransitionStyle(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
        transaction.commitAllowingStateLoss();
        currentId = index;
    }
    
    
}