AndroidX對ViewPager懶加載的影響及解決方案

閱讀前請點擊右上角“關注”,每天免費獲取Android知識解析及面試解答。Android架構解析,只做職場乾貨,完全免費分享!


AndroidX對ViewPager懶加載的影響及解決方案

本文主要是講解遷移到AndroidX之後,對原本的ViewPager懶加載造成的影響,和如何進行優化。參考的項目來自

波瀾步驚 的文章 《手把手講解 ViewPager懶加載》

最後的代碼修改對比也是來自大神的文章,建議先看一下再過來看本文

一、為什麼要遷移為AndroidX

根據官方說明,AndroidX是對原始Android支持庫(android.support.*)進行了重大改進和統一管理,舊的庫依然能用,但是新庫的開發都將會在AndroidX中進行,所以建議還是遷移到AndroidX。


具體如何遷移,本文在此不做詳細說明,請查看官方文檔

二、遷移之後的區別

遷移之後出現問題,主要是因為FragmentPagerAdapter的文件有所改動

1 初始化

舊版:


新版:


可以看到初始化的方式添加了一個@Deprecated (廢棄)的註解,就是告訴大家不要用這種方式進行初始化了。那麼應該怎麼進行初始化呢?


這裡就可以看到,初始化的時候,除了需要傳入fm,同時還需要傳一個behavior,讓我們來看看Behavior具體是哪些值?


根據註釋可以知道

當behavior == BEHAVIOR_SET_USER_VISIBLE_HINT 時,Fragment切換時,會觸發setUserVisibleHint。這個效果和[圖片上傳失敗...(image-498b78-1587693534449)]

的效果一樣,也就是說,如果你不想修改原來懶加載的邏輯,只需要這麼寫

<code>FragmentPagerAdapter adapter = new FragmentPagerAdapter(fm);
或者
FragmentPagerAdapter adapter = new FragmentPagerAdapter(fm, BEHAVIOR_SET_USER_VISIBLE_HINT);

/<code>

但是,我們看到了BEHAVIOR_SET_USER_VISIBLE_HINT也被標識了@Deprecated (廢棄),建議我們使用BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT。所以[圖片上傳失敗...(image-7fe658-1587693534449)]

初始化方式是:

<code>FragmentPagerAdapter adapter = new FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);

/<code>

而這時候會用到生命週期狀態標識Lifecycle.State。

2 FragmentPageAdapter初始化Fragment

<code>@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
//...省略非重點代碼
if (mBehavior == BEHAVIOR_SET_USER_VISIBLE_HINT) {
//舊版本,觸發setUserVisibleHint
fragment.setUserVisibleHint(false);
}

mFragments.set(position, fragment);
//關鍵句,添加Fragment進入事物list
mCurTransaction.add(container.getId(), fragment);

if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
//AndroidX,設置初始化執行到onStart()就停止了
mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.STARTED);
}

return fragment;
}

/<code>

追蹤進入mCurTransaction.add(container.getId(), fragment);方法


<code> void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
//...省略非重點代碼
addOp(new Op(opcmd, fragment));
}

/<code>


添加的是一個Op對象,看看Op是如何初始化的。

<code>Op(int cmd, Fragment fragment) {
this.mCmd = cmd;
this.mFragment = fragment;
//初始化執行到onResume()
this.mOldMaxState = Lifecycle.State.RESUMED;
this.mCurrentMaxState = Lifecycle.State.RESUMED;
}

/<code>

到這裡,我們就能明白瞭如果是舊版本,Fragment初始化的時候,默認會執行到onResume(),而AndroidX只會執行到onStart(),所以我們遷移到AndroidX之後,不需要全都依靠setUserVisibleHint()來判斷當前頁面是否顯示,我們可以根據onResume()來判斷。

3 遷移到AndroidX之後,BaseFragment相應的修改

<code>@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
mRoot = inflater.inflate(getLayoutId(), container, false);
Log.d(getLifeCycleTag(), "onCreateView");
initView(mRoot);
//在View創建完畢之後,isViewCreate 要變為true
isViewCreated = true;
//下面2段代碼可以刪除
//if (!isHidden() && getUserVisibleHint())
//dispatchVisibleState(true);
return mRoot;
}

@Override
public void onResume() {
super.onResume();
Log.d(getLifeCycleTag(), "onResume");

/* 舊版本
if (!isFirstVisible) {
if (!isHidden() && !currentVisibleState && getUserVisibleHint())
dispatchVisibleState(true);
}
*/
//新版本
if (!isHidden() && !currentVisibleState && isResumed()) {
dispatchVisibleState(true);
}
}

@Override
public void onPause() {
MobclickAgent.onPageEnd(this.getClass().getName());
super.onPause();
Log.d(tag,"onPause: ");
/* 舊版本
if (currentVisibleState && !isResumed()) {
dispatchVisibleState(false);
}
*/
//新版本
if (currentVisibleState && !isResumed()) {
dispatchVisibleState(false);
}
}
//其他不需要更改

/<code>

三、總結

遷移到AndroidX,主要改變的是FragmentPagerAdapter對Fragment的初始化方式進行了優化,所以才需要進行這樣修改,其實問題不難,順著邏輯看一下源碼就能發現區別啦。希望對大家有所幫助,如果文章有不足之處,請不吝指出,謝謝。

四、鳴謝

感謝 波瀾步驚 的文章 《手把手講解 ViewPager懶加載》ViewPager懶加載寫得很詳細,易懂。

感謝 享學課堂 avlin老師 提供的demo 以及視頻


分享到:


相關文章: