1.前言

昨天談了BaseActivity的封裝,
Android談談封裝那些事--BaseActivity和BaseFragment(一)
有很多小伙伴提了很多建議,比如:

  • 通用標題欄可以自定義View而不放在Base里面,代碼更統一
  • BaseEventActivity里面應該留出開關保證不需要Bus的Activity使用
  • BaseStatusActivity里面就一個方法沒必要新建一個
  • 還有一些小的細節

在這里感謝大家的建議了啊。我修改了一部分,后面會慢慢優化,最后在HLibrary里面貼出最優代碼。還有那個BaseStatusActivity(沉浸欄)的也會繼續優化的。接下來談談BaseFragment的封裝,其實主要還是關於Fragment的懶加載問題。

2.Fragment相關知識點

  • 生命周期
  • Fragment的使用:靜態、動態
  • Fragment應注意到的問題
  • ......

在這里就不詳細介紹了,想了解的可以看我的這篇文章:

你真的會用Fragment了么?-Fragment解析

1.Fragment使用場景

我們可以看到市場的APP一般都是用底部Tab+fragment切換為整體架子的,或者通過viewpager作為容器嵌套fragment,再復雜點的就是fragment嵌套fragment,某書、某條等等都是這樣;

2.遇到的問題

這樣的話我們遇到的問題就是當fragment很多組合使用的時候,每個fragment里面都會加載數據或者執行動畫等比較復雜的業務邏輯時,導致我們的APP進入時屏幕卡頓,性能很差,一點都不流暢。即便是我們在使用viewpager作為容器的時候設置預加載setOffscreenPageLimit()這個方法,其實你會發現根本不會起作用。
至於viewpager這個預加載方法為什么不行?我們可以看一下viewpager源碼:

 


我們可以看到DEFAULT_OFFSCREEN_PAGES 這里就定義了默認值是1,如果你調用該方法傳進來的值小於1是無效的,會被強行的拽回1。而且DEFAULT_OFFSCREEN_PAGES 這個值是private的,子類繼承ViewPager也是不可見的。
網上有的說可以將viewpager的源碼復制下來粘到自己的類里面將這個默認值改為0,這個目前還沒試過,即使可以感覺也有些別扭,更何況我們使用場景也不一定需要viewpager呢

 

3.Fragment懶加載

這是靠Fragment里有一個setUserVisibleHint(boolean isVisibleToUser)的方法,我們可以在這個方法里做判斷,當其True可見時(即切換到某一個具體Fragment)時才去加載數據,這樣可以省流量。
具體怎么去操作呢?

  • 預加載初始化數據和組件等輕量操作
  • 切換tab到第一次可見時執行網絡請求
  • 四種狀態:第一次可見狀態、可見狀態、第一次不可見狀態、不可見狀態
  • 銷毀時處理解注冊、銷毀廣播等問題

3.BaseFragment封裝

1.初始化xml文件

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

2.注解綁定以及初始化組件

@Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); ButterKnife.bind(this,view); initViewsAndEvents(view); } protected abstract void initViewsAndEvents(View view);

3.四種“見”的狀態拆分

@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();

4.最后解注冊銷毀等工作

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

5.跳轉界面等方法

/** * 打開一個Activity 默認 不關閉當前activity */ public void gotoActivity(Class<?> clz) { gotoActivity(clz, false, null); } public void gotoActivity(Class<?> clz, boolean isCloseCurrentActivity) { gotoActivity(clz, isCloseCurrentActivity, null); } public void gotoActivity(Class<?> clz, boolean isCloseCurrentActivity, Bundle ex) { Intent intent = new Intent(mActivity, clz); if (ex != null) intent.putExtras(ex); startActivity(intent); if (isCloseCurrentActivity) { mActivity.finish(); } }

最后提一個小問題吧:就是說如果你沒有用Fragment懶加載的話而是用的viewpager的預加載,如果你沒有自己定義默認預加載個數的話,那么默認肯定是會提前加載的,加入你當前fragment相鄰的fragment里面有動畫或者視頻播放的話,切換到當前fragment時候下個fragment里面的動畫或者視頻就已經開始執行了,注意一下。
到此我的base就告一段落了,很多不合理的地方,我接下來私下也會去聽取小伙伴們的意見進行修改,然后最后在HLibrary里面貼出來的,非常感謝大家。