Android fragment 重疊問題的解決方法

由於這個項目的首頁是類似微信的那種 tab 有四個界面 聯繫人,消息,動態,設置四個界面,因爲有頻繁的切換,所以就沒有使用replace 和 remve方法。而是通過hide,show方式,這樣雖然不會重複創建Fragment了,節省了view重繪的性能問題。
但是這樣就容易導致一個問題:就是程序長時間後臺導致fragment重疊。

    問題描述:
                    app運行的時候,按下home鍵,然後清理內存。 
                    或者,按下home之後,打開其他的一些佔內存的app,然後把本app的內存擠掉了。

    解決方案:  (這個問題google了很多帖子,發現寫的很亂,沒幾個好用的,後來我就一個個的試驗,從兩個帖子中找到有用的方法。綜合如下:)
                    1:給每個Fragment加一個Tag;
                    2.在onCreate(Bundle savedInstanceState)中判斷Bundle savedInstanceState是否不爲空;
                    3.不爲空則進行find Tag,重新給幾個frament賦值。
                    
1.
switch (index) {
  case 0:
   // 當點擊了消息tab時,改變控件的圖片和文字顏色
   messageImage.setImageResource(R.drawable.message_selected); 
   messageText.setTextColor(Color.WHITE);
   if (messageFragment == null) {
    // 如果MessageFragment爲空,則創建一個並添加到界面上
    messageFragment = new MessageFragment();
    transaction.add(R.id.content, messageFragment, FRAGMENT_TAG[index]);
   } else {
    // 如果MessageFragment不爲空,則直接將它顯示出來
    transaction.show(messageFragment);
   }
   break;


2.  3.
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  requestWindowFeature(Window.FEATURE_NO_TITLE);
  setContentView(R.layout.activity_main);
  // 初始化佈局元素
  initViews();
  fragmentManager = getFragmentManager();
        if (savedInstanceState != null) {
            //讀取上一次界面Save的時候tab選中的狀態
            selindex=savedInstanceState.getInt(PRV_SELINDEX,selindex);
            messageFragment = (MessageFragment) fragmentManager.findFragmentByTag(FRAGMENT_TAG[0]);
            contactsFragment = (ContactsFragment) fragmentManager.findFragmentByTag(FRAGMENT_TAG[1]);
            newsFragment = (NewsFragment) fragmentManager.findFragmentByTag(FRAGMENT_TAG[2]);
            settingFragment = (SettingFragment) fragmentManager.findFragmentByTag(FRAGMENT_TAG[3]);
        }
        // 選中index
  setTabSelection(selindex);
 }

//那麼文中有幾處藍色高亮的代碼  請看如下

    /**
     * Fragment的TAG 用於解決app內存被回收之後導致的fragment重疊問題
     */
    private static final  String[] FRAGMENT_TAG = {"msgfrag","contacfrag","actfrag","settfrag"};





PS:
            補充一點:PRV_SELINDEX,selindex  是用於恢復上一次界面Save的時候tab選中的狀態


    @Override
    protected void onSaveInstanceState(Bundle outState) {
        //保存tab選中的狀態
        outState.putInt(PRV_SELINDEX,selindex);
        super.onSaveInstanceState(outState);
    }


    /**
     * 上一次界面 onSaveInstanceState 之前的tab被選中的狀態 key 和 value
     */
    private static final  String PRV_SELINDEX="PREV_SELINDEX";
    private int selindex=0;


OK,當你配置好了tag之後,再addfrag的時候使用了tag,Act執行saveInstancestates 的時候就會自動按tag給你保存frag的狀態了。
那麼,你如果覺得這種方式不是很好,你這tag也可以不要在add的時候使用,你可以在Act  onSAveInstancestate的時候,用FragmentMange手動保存,
然後在act,oncreate的時候bundle不爲空 就用之前記錄的幾個tag手動打開。


這是這個act裏面的Frag的問題。

2.那麼frag中嵌套frag的時候,也是需要保存與恢復的呢?

frag中的frag是子frag,外層的frag是主frag。先這麼叫吧,這樣好區分。


一樣的道理 ,代碼都很像,你把主frag當成act,只是getSurpportFragmentManager的時候 ,不用這個方法,有個getChildFragmentManger,大概是這麼寫的吧,我記不清是getChildFfragmentMnager還是getSurpportChildFragmentmanager了,反正你找下就行了。

這裏就不貼代碼了,畢竟很act中潛逃frag代碼都很像,邏輯都是一樣的。

3.有點要注意的是viewpager中潛逃frag,這樣的話 記得把Viewpager的緩存數設置爲 frag 數目減一。viewpager有個方法是setoffscreenpagelimit方法,可以設置緩存數目,這個方法看viewpager的源碼,意思是緩存下來未顯示的子控件,所以viewpager肯定是有一個是顯示的,其他的要緩存,那麼緩存數是 子控件的數目減一。  而且從viewpager的源碼上看,這個方法裏,最小的數字是1。  緩存數 默認也是1,你不改的話 他會 有一些問題,就是你這邊的frag因爲沒有被緩存 會被自動釋放,然後重新新建,有些邏輯執行的就比較多了 。
viewpager內嵌套frag之後,每次pagerAdapger  執行notifychange的時候會有個問題就是特麼的,原來的舊的fragment會先釋放,執行ondettach   ondestory方法  ,然後重新創建,要注意。


無恥的奉上我的公衆號二維碼,沒事聽我給你扯扯段子。


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