Fragment add show hide 異常銷燬後重疊問題

在新項目的開發過程中,無意間點了幾下首頁的底部導航 發現fragment 竟然空白不展示了,what!!

這個新項目我首頁導航用的是 ViewPager+Fragment+BottomNavigationView

ViewPager進行了自定義,保證它不能滑動和間隔頁面(比如 目前在1 點擊到4的時候)的時候不會有滑動的動畫

代碼貼出來

import android.content.Context;
import android.content.res.TypedArray;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;

import com.cmcm.teacherconsumers.R;

/**
 * @author wavewave
 * @CreateDate: 2019/3/20 7:04 PM
 * @Description:
 * @Version: 1.0
 */
public class MyViewPager extends ViewPager {
    private boolean isCanScroll = false;

    public MyViewPager(@NonNull Context context) {
        super(context);
    }

    public MyViewPager(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LazyViewPager);
        setInitLazyItemOffset(a.getFloat(R.styleable.LazyViewPager_init_lazy_item_offset, DEFAULT_OFFSET));
        a.recycle();
    }

    /**
     * 設置其是否能滑動換頁
     *
     * @param isCanScroll false 不能換頁, true 可以滑動換頁
     */
    public void setScanScroll(boolean isCanScroll) {
        this.isCanScroll = isCanScroll;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return isCanScroll && super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return isCanScroll && super.onTouchEvent(ev);

    }

    @Override
    public void setCurrentItem(int item, boolean smoothScroll) {
        super.setCurrentItem(item, false);
    }

    @Override
    public void setCurrentItem(int item) {
        super.setCurrentItem(item, false);
    }
}

然後在做到接口的時候發現一個問題就是fragment 切換後會一直重新創建,想起ViewPager有個

setOffscreenPageLimit(); 方法 可以設置緩存數量

這個設置後 它會提前加載的。。。根據情況使用

對於我來說,這種一打開就請求所有接口的,,,我怕老大打死我。

於是想起了好久之前的開源項目 懶加載  LazyFragmentPagerAdapter

地址過去看看

導入進去使用。不錯不錯確實是懶加載 生命週期都不一樣。

但是今天點出bug了,操作流程是

我的標籤一共是四個,打開頁面

點擊第四個標籤,然後再點擊第二個標籤,空白了。。。。

生命週期都沒有走,debug找找 好像是懶加載機制裏面的問題,

因爲我比較懶,所以就換最古老的寫法了。

Fragment  add(), show(),hide()

因爲之前也寫過好多次,這次變抽出方法來

加入的方法

 private void showFragment(Fragment fragment, String tag) {
        if (TextUtils.isEmpty(tag)) return;
        hideFragment();
        if (fragment == null) {
            if (tag.equals(fragmentTag[1])) {
                chatFragment = ChatFragment.newInstance("", "");
                getSupportFragmentManager().beginTransaction().add(R.id.main_ll, chatFragment, fragmentTag[1]).commit();
            } else if (tag.equals(fragmentTag[2])) {
                studentFragment = StudentFragment.newInstance("", "");
                getSupportFragmentManager().beginTransaction().add(R.id.main_ll, studentFragment, fragmentTag[2]).commit();
            } else if (tag.equals(fragmentTag[3])) {
                myFragment = MyFragment.newInstance("", "");
                getSupportFragmentManager().beginTransaction().add(R.id.main_ll, myFragment, fragmentTag[3]).commit();
            } else {
                homeFragment = HomeFragment.newInstance("", "");
                getSupportFragmentManager().beginTransaction().add(R.id.main_ll, homeFragment, fragmentTag[0]).commit();
            }
        } else {
            getSupportFragmentManager().beginTransaction().show(fragment).commit();
        }
    }

隱藏的方法

 private void hideFragment() {
        FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
        if (homeFragment != null) fragmentTransaction.hide(homeFragment);
        if (chatFragment != null) fragmentTransaction.hide(chatFragment);
        if (studentFragment != null) fragmentTransaction.hide(studentFragment);
        if (myFragment != null) fragmentTransaction.hide(myFragment);
        fragmentTransaction.commit();
    }

寫這個要注意一下,如果當前activity 被異常銷燬重建的時候,會有重疊問題

打開手機的開發者選項,往下拉 找到 應用下面的 不保留活的 開關打開就可以測試拉(我的手機是華爲,其他也會有這個選項)

於是動手解決一下,思路很簡單

就是在它重建的時候,在FragmentManager通過Tag重新把 fragment對象找回來就好了

我們還要保證銷燬前的樣子 所以還要手動去保存一個 索引

重寫 onSaveInstanceState(Bundle outState)


    //記錄當前選中的 fragment 索引用於異常銷燬 恢復
    private int selectPosition = -1;

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

然後在 oncreate的時候恢復 我封裝的Base 所以自己寫的方法 叫做 afterCreate

  @Override
    protected void afterCreate(Bundle savedInstanceState) {
        if (savedInstanceState != null) {//處理activity 異常銷燬恢復 fragment
            selectPosition = savedInstanceState.getInt(SELECT_FRAGMENT, -1);
            saveFragment(selectPosition);
        } else {
            showFragment(homeFragment, fragmentTag[0]);
        }
        mainBnv.setOnNavigationItemSelectedListener(this);
    }

    /**
     * 用於恢復 activity 異常銷燬的fragment
     *
     * @param anInt
     */
    private void saveFragment(int anInt) {

        homeFragment = (HomeFragment) getSupportFragmentManager().findFragmentByTag(fragmentTag[0]);
        chatFragment = (ChatFragment) getSupportFragmentManager().findFragmentByTag(fragmentTag[1]);
        studentFragment = (StudentFragment) getSupportFragmentManager().findFragmentByTag(fragmentTag[2]);
        myFragment = (MyFragment) getSupportFragmentManager().findFragmentByTag(fragmentTag[3]);
        switch (anInt) {
            case 0:
            default:
                showFragment(homeFragment, fragmentTag[0]);
                break;
            case 1:
                showFragment(chatFragment, fragmentTag[1]);
                break;
            case 2:
                showFragment(studentFragment, fragmentTag[2]);
                break;
            case 3:
                showFragment(myFragment, fragmentTag[3]);
                break;
        }
    }

當然可能 有些不好上手 於是我寫個demo放到github 上

https://github.com/renwavewave/FragmentDemo

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