天天看點

封裝篇——Fragment懶加載

為什麼要做fragment的懶加載封裝呢???一個字“懶”!!!

我老大告訴我:不會偷懶的程式員不是個好廚師 ^~^ ^~^ ^~^

我們可能會以 viewpager(或其他容器)與多個Fragment組合使用,相信使用過的猿(媛)友們都碰到過下面的這些問題:

1. 預加載Fragment時,也就是加載不可見的Fragment時,該不可見的Fragment初始化資料和頁面可能占用了大量的資源;

2. 如果當頁面内有動畫或者是存在其它持續性的操作,fragment的狀态切換時操作的開關問題;

3. 初始化時代碼量大的問題,沒錯 在我看來 連初始化寫

inflater.inflate(R.layout.xxx,container,false)

都是多餘重複的操作;

封裝篇——Fragment懶加載

既然列出了我們需要解決的問題,下面我将從 需要了解的知識點、封裝生命周期、常用方法、還有進階擴充方法 四點,講講我是如何進行封裝的

封裝篇——Fragment懶加載

需要了解的知識點

沒錯,進行封裝之前,你必須對你要封裝的對象有一個比較稍微深入一點的了解,不然隻能是盲人摸象了。

封裝篇——Fragment懶加載

1. Fragment的生命周期:最起碼要知道’被建立’、’對使用者可見’、’進入“背景模式’、’被銷毀’這四個操作下它會經曆哪些狀态。(可檢視:http://www.cnblogs.com/purediy/p/3276545.html)

2. 既然是懶加載,我們必須知道setUserVisibleHint這個方法。(API位址:http://androiddoc.qiniudn.com/reference/android/app/Fragment.html#setUserVisibleHint(boolean) );

知道了生命周期是如何運作了,我們來做下一步的事情:封裝 Fragment的生命周期。

封裝懶加載的生命周期

我們要達到的具體效果:

1. 預加載時隻做輕量的初始化;

2. 第一次可見狀态下才開始加載數;

3. 在把生命周期拆成 “可見”與“不可見”狀态;

4. 使開發更加關注業務本身,而不是被繁瑣的生命周期拖延時間;

我們大概能抽出幾個方法出來了,如下圖:

封裝篇——Fragment懶加載

初始化 xml,初始化 UI

@Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        if (getContentViewLayoutID() != ) {
            return inflater.inflate(getContentViewLayoutID(), null);
        } else {
            return super.onCreateView(inflater, container, savedInstanceState);
        }
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        initViewsAndEvents(view);
    }

    protected abstract int getContentViewLayoutID();

    protected abstract void initViewsAndEvents(View view);
           

如果你用了 Dagger、RoboGuice、ButterKnife 這些依賴注入的話,那 initViewsAndEvents(View view)可以不做任何事情

第一次可見狀态、可見狀态、第一次不可見狀态、不可見狀态

private boolean isFirstVisible = true;
    private boolean isFirstInvisible = true;
    private boolean isPrepared;

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        initPrepare();
    }

    private synchronized void initPrepare() {
        if (isPrepared) {
            onFirstUserVisible();
        } else {
            isPrepared = true;
        }
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser) {
            if (isFirstVisible) {
                isFirstVisible = false;
                initPrepare();
            } else {
                onUserVisible();
            }
        } else {
            if (isFirstInvisible) {
                isFirstInvisible = false;
                onFirstUserInvisible();
            } else {
                onUserInvisible();
            }
        }
    }

    protected abstract void onFirstUserVisible();
    protected abstract void onUserVisible();
    private void onFirstUserInvisible() { }
    protected abstract void onUserInvisible();
           

這邊 準備時可以用個同步鎖: synchronized

銷毀 Fragment 時,可能需要做些 解除廣播綁定,服務之類的鬼東西:

@Override
    public void onDestroy() {
        DetoryViewAndThing();
        super.onDestroy();
    }

    protected abstract void DetoryViewAndThing();
           

好了 ,有了以上的基礎,我們的懶加載原型1.0已經可以使用了,大家看個使用的例子:

public class ImageFragment extends BaseLazyFragment{
    ...

    @Override
    protected int getContentViewLayoutID() {
        return R.layout.fragment_images;
    }

    @Override
    protected void onFirstUserVisible() {
       //  加載資料 / 開啟動畫 / 廣播.....
    }

    @Override
    protected void onUserVisible() {
        //開啟動畫 / 廣播.....
    }

    @Override
    protected void onUserInvisible() {
      //暫停動畫 / 暫停廣播.....
    }

    @Override
    protected void initViewsAndEvents(View view) {
       //.........
        mRecyclerView = (RecyclerView) view.findViewById(R.id.fragment_images_list_list_view);
    }
       //做些銷毀動作
    @Override
    protected void DetoryViewAndThing() {
        if (null != mImagesListPresenter) {
            mImagesListPresenter.detachView();
            mImagesListPresenter = null;
        }
    }
           

接下來我們來封裝些通用的方法,如 頁面跳轉、吐司、dialog基礎方法….

公共方法:

封裝篇——Fragment懶加載

這一段很好了解,看代碼就能懂,就不再作過多說明

protected void readyGo(Class<?> clazz) {
    Intent intent = new Intent(getActivity(), clazz);
    startActivity(intent);
}

protected void readyGo(Class<?> clazz, Bundle bundle) {
    Intent intent = new Intent(getActivity(), clazz);
    if (null != bundle) {
        intent.putExtras(bundle);
    }
    startActivity(intent);
}

protected void readyGoForResult(Class<?> clazz, int requestCode) {
    Intent intent = new Intent(getActivity(), clazz);
    startActivityForResult(intent, requestCode);
}

protected void readyGoForResult(Class<?> clazz, int requestCode, Bundle bundle) {
    Intent intent = new Intent(getActivity(), clazz);
    if (null != bundle) {
        intent.putExtras(bundle);
    }
    startActivityForResult(intent, requestCode);
}

protected void showToast(String msg) {
    if (null != msg && !StringUtils.isEmpty(msg)) {
        Snackbar.make(((Activity) mContext).getWindow().getDecorView(), msg, Snackbar.LENGTH_SHORT).show();
    }
}
           

進階方法:

統一的基礎頁面封裝:

封裝篇——Fragment懶加載

頁面替換暫時還有些問題(從錯誤頁面/loading頁面 恢複正常頁面後,UI層級不會變深,但 繪制層級加深了,這是個bug。)

但還是供大家參考下這個思想:

private VaryViewHelperController mVaryViewHelperController = null; // 一個封裝的 視圖 替換方法
/**
 * 得到需要展示的父View
 */
protected abstract View getLoadingTargetView();
/**
 * @param toggle
 */
protected void toggleShowLoading(boolean toggle, String msg) {
    if (null == mVaryViewHelperController) {
        throw new IllegalArgumentException("You must return a right target view for loading");
    }

    if (toggle) {
        mVaryViewHelperController.showLoading(msg);
    } else {
        mVaryViewHelperController.restore();
    }
}

/**
 * toggle show empty
 *
 * @param toggle
 */
protected void toggleShowEmpty(boolean toggle, String msg, View.OnClickListener onClickListener) {
    if (null == mVaryViewHelperController) {
        throw new IllegalArgumentException("You must return a right target view for loading");
    }

    if (toggle) {
        mVaryViewHelperController.showEmpty(msg, onClickListener);
    } else {
        mVaryViewHelperController.restore();
    }
}

/**
 * toggle show error
 *
 * @param toggle
 */
protected void toggleShowError(boolean toggle, String msg, View.OnClickListener onClickListener) {
    if (null == mVaryViewHelperController) {
        throw new IllegalArgumentException("You must return a right target view for loading");
    }

    if (toggle) {
        mVaryViewHelperController.showError(msg, onClickListener);
    } else {
        mVaryViewHelperController.restore();
    }
}

/**
 * toggle show network error
 *
 * @param toggle
 */
protected void toggleNetworkError(boolean toggle, View.OnClickListener onClickListener) {
    if (null == mVaryViewHelperController) {
        throw new IllegalArgumentException("You must return a right target view for loading");
    }

    if (toggle) {
        mVaryViewHelperController.showNetworkError(onClickListener);
    } else {
        mVaryViewHelperController.restore();
    }
}
           

現在一個實用簡便的懶加載Fragment就完成了….

封裝篇——Fragment懶加載

說明得比較粗糙,後續會修改一些措辭與排版,請大家多多見諒。

祝大家愚人節快樂!!!

轉載請标明出處:

http://blog.csdn.net/sinat_15877283/article/details/51037987;

本文出自: 【溫利東的部落格】

繼續閱讀