Activity中Fragment重疊問題

  圖1                         圖2

先簡單說一下我碰到的問題,圖1是我的主界面,採用底部導航+FrameLayout來實現Fragment的切換,當app在某一個界面崩潰後,回到了主界面,就出現了Fragment重疊問題,如圖2。  因爲我之前還有一個項目也是採用的底部導航+FrameLayout,但當初我在開發的時候並沒有碰到這種bug,所以打開之前開發的那個app搗鼓了一會,也成功出現了這個bug,當然不是崩潰引起的,而是通過橫豎屏切換。

       仔細想了一下,無論頁面崩潰還是橫豎屏切換,都要重走activity的生命週期,就相當於重新打開了這個界面,按道理一切都應該重新開始纔對,爲什麼裏面的Fragment沒有被銷燬。帶着疑問我默默打開瀏覽器百度了一下。看了幾篇博客之後,知道了問題所在。這兩篇博客比較靠譜點  https://blog.csdn.net/u011734444/article/details/53347265   

                                                    https://blog.csdn.net/yuzhiqiang_1993/article/details/75014591

       原因:當我們旋轉屏幕的時候,activity會被銷燬並重新創建,並且在銷燬之前執行了onSaveInstanceState(Bundle outState)這個方法。這個方法會保存activity的一些信息,其中就包括添加過的fragment,當activity被重新創建時,會初始化其中的變量,這個時候點擊底部導航的話會重新去添加fragment,也就導致了重疊的問題。

       既然Fragment沒有被銷燬並且被保存在了bundle中,那我們就可以把它們取出來進行復用,並且需要知道從bundle中取出來的是哪個Fragment,所以我們在添加Fragment的時候需要設置Tag,這樣就知道取出來的是哪個Fragment了。

ft.add(R.id.main_framlayout, fragment, tag);//第三個參數就是tag

首先是添加Fragment

private FragmentManager fm = getSupportFragmentManager();
private FragmentTransaction ft;
//Fragment集合
private Fragment[] fragments = new Fragment[]{new HomeFragment(), new ReportFragment(), new MineFragment()};

private Fragment mCurrentShowFrag;//當前展示的fragment
private int currentFragPosition = 0;//記錄當前展示fragment的position 默認第一個爲0

//判斷當前要顯示fragment是否被添加,沒有則添加,已添加直接show()
private void showFragment(int position) {
        ft = fm.beginTransaction();//不可作爲全局變量,每次切換Fragment的時候,都必須開啓一個新事務
        Fragment fragment = fragments[position];

        if (mCurrentShowFrag != null) {
            ft.hide(mCurrentShowFrag);
        }
        
        if (!fragment.isAdded()) {
            Logger.i("", "------------noadd");
            ft.add(R.id.main_framlayout, fragment, "" + position);//第三個參數就是fragment所對應的tag
        } else {
            Logger.i("", "------------added");
            ft.show(fragment);
        }
        mCurrentShowFrag = fragment;
        ft.commit();
}

       當頁面崩潰或橫豎屏切換引起界activity重新加載 ,之前的Fragment並沒有被銷燬,只是保存到了savedInstanceState,當重走onCeate方法時,在savedInstanceState根據tag取到對應的fragment

private void initFragmentList(Bundle savedInstanceState) {
        if (savedInstanceState != null) {
            currentFragPosition = savedInstanceState.getInt("position");//恢復崩潰之前framgent所對應的position
            mCurrentShowFrag = fragments[currentFragPosition];//恢復底部導航欄的正確選中位置
            bottom_bar.setFirstSelectedPosition(currentFragPosition).initialise();
            for (int i = 0; i < fragments.length; i++) {
                //這裏需要判斷fragment之前有沒有被添加,如果沒有添加,則通過tag是取不到fragment的,爲null
                if (fm.findFragmentByTag("" + i) != null) {
                    fragments[i] = fm.findFragmentByTag("" + i);
                }
            }
        }
}

 

到這裏就不會出現fragment的重疊問題了,當然還有一個小問題需要處理一下,如果我崩潰之前位於第三個Fragment,但是重新加載後顯示的是第一個Fragment,並且底部導航也是第一個被選中,所以需要記錄一下當前顯示fragment的索引currentFragPosition ,並且在崩潰重走onSavedInstance()方法的時候進行保存,然後在onCreate()中重新賦值,通過currentFragPosition來決定顯示哪個Fragment,底部導航欄哪一個被選中

@Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initFragmentList(savedInstanceState);
        showFragment(currentFragPosition);
}   


 @Override
protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("position", currentFragPosition);
}

  多一點記錄,多一點收穫,多一份感悟。ヾ(◍°∇°◍)ノ゙加油!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章