1.前言
昨天談了BaseActivity的封裝,
Android談談封裝那些事–BaseActivity和BaseFragment(一)
有很多小夥伴提了很多建議,比如:
- 通用標題欄可以自定義View而不放在Base裡面,程式碼更統一
- BaseEventActivity裡面應該留出開關保證不需要Bus的Activity使用
- BaseStatusActivity裡面就一個方法沒必要新建一個
- 還有一些小的細節
在這裡感謝大家的建議了啊。我修改了一部分,後面會慢慢優化,最後在HLibrary裡面貼出最優程式碼。還有那個BaseStatusActivity(沉浸欄)的也會繼續優化的。接下來談談BaseFragment的封裝,其實主要還是關於Fragment的懶載入問題。
2.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裡面貼出來的,非常感謝大家。