本文主要是講解遷移到AndroidX之后恩闻,對原本的ViewPager懶加載造成的影響赞赖,和如何進行優(yōu)化栏尚。參考的項目來自
最后的代碼修改對比也是來自大神的文章到逊,建議先看一下再過來看本文
一吮便、為什么要遷移為AndroidX
根據(jù)官方說明骆姐,AndroidX是對原始Android支持庫(android.support.*)進行了重大改進和統(tǒng)一管理镜粤,舊的庫依然能用,但是新庫的開發(fā)都將會在AndroidX中進行玻褪,所以建議還是遷移到AndroidX肉渴。
具體如何遷移,本文在此不做詳細說明带射,請查看官方文檔
二同规、遷移之后的區(qū)別
遷移之后出現(xiàn)問題,主要是因為FragmentPagerAdapter的文件有所改動
1 初始化
舊版:
新版:
可以看到初始化的方式添加了一個@Deprecated (廢棄)的注解窟社,就是告訴大家不要用這種方式進行初始化了券勺。那么應(yīng)該怎么進行初始化呢?
這里就可以看到灿里,初始化的時候关炼,除了需要傳入fm,同時還需要傳一個behavior匣吊,讓我們來看看Behavior具體是哪些值儒拂?
根據(jù)注釋可以知道
當behavior == BEHAVIOR_SET_USER_VISIBLE_HINT 時,F(xiàn)ragment切換時色鸳,會觸發(fā)setUserVisibleHint社痛。
這個效果和的效果一樣,也就是說命雀,如果你不想修改原來懶加載的邏輯蒜哀,只需要這么寫
FragmentPagerAdapter adapter = new FragmentPagerAdapter(fm);
或者
FragmentPagerAdapter adapter = new FragmentPagerAdapter(fm, BEHAVIOR_SET_USER_VISIBLE_HINT);
但是,我們看到了BEHAVIOR_SET_USER_VISIBLE_HINT也被標識了@Deprecated (廢棄)咏雌,建議我們使用BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT凡怎。所以初始化方式是:
FragmentPagerAdapter adapter = new FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
而這時候會用到生命周期狀態(tài)標識Lifecycle.State校焦。
2 FragmentPageAdapter初始化Fragment
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
//...省略非重點代碼
if (mBehavior == BEHAVIOR_SET_USER_VISIBLE_HINT) {
//舊版本,觸發(fā)setUserVisibleHint
fragment.setUserVisibleHint(false);
}
mFragments.set(position, fragment);
//關(guān)鍵句,添加Fragment進入事物list
mCurTransaction.add(container.getId(), fragment);
if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
//AndroidX,設(shè)置初始化執(zhí)行到onStart()就停止了
mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.STARTED);
}
return fragment;
}
追蹤進入mCurTransaction.add(container.getId(), fragment);方法
void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
//...省略非重點代碼
addOp(new Op(opcmd, fragment));
}
添加的是一個Op對象赊抖,看看Op是如何初始化的统倒。
Op(int cmd, Fragment fragment) {
this.mCmd = cmd;
this.mFragment = fragment;
//初始化執(zhí)行到onResume()
this.mOldMaxState = Lifecycle.State.RESUMED;
this.mCurrentMaxState = Lifecycle.State.RESUMED;
}
到這里,我們就能明白了如果是舊版本氛雪,F(xiàn)ragment初始化的時候房匆,默認會執(zhí)行到onResume(),而AndroidX只會執(zhí)行到onStart()报亩,所以我們遷移到AndroidX之后浴鸿,不需要全都依靠setUserVisibleHint()來判斷當前頁面是否顯示,我們可以根據(jù)onResume()來判斷弦追。
3 遷移到AndroidX之后岳链,BaseFragment相應(yīng)的修改
@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創(chuàng)建完畢之后,isViewCreate 要變?yōu)閠rue
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);
}
}
//其他不需要更改
三劲件、總結(jié)
遷移到AndroidX掸哑,主要改變的是FragmentPagerAdapter對Fragment的初始化方式進行了優(yōu)化,所以才需要進行這樣修改零远,其實問題不難苗分,順著邏輯看一下源碼就能發(fā)現(xiàn)區(qū)別啦。希望對大家有所幫助牵辣,如果文章有不足之處摔癣,請不吝指出,謝謝纬向。
四择浊、鳴謝
感謝 波瀾步驚 的文章 《手把手講解 ViewPager懶加載》ViewPager懶加載寫得很詳細,易懂逾条。
感謝 享學課堂 avlin
老師 提供的demo 以及視頻