天天看點

Activity中Fragment重疊問題

Activity中Fragment重疊問題

  圖1                       

Activity中Fragment重疊問題

  圖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);
}
           

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

繼續閱讀