背景:項(xiàng)目中每個(gè)頁(yè)面多個(gè)地方使用到Fragment棍弄,有的是在viewpager中,有的自己進(jìn)行管理疟游;項(xiàng)目運(yùn)行一段時(shí)間后想對(duì)fragment進(jìn)行懶加載處理呼畸,很早之前只對(duì)ViewPager中的Fragment進(jìn)行過(guò)處理,結(jié)果在處理過(guò)程中遇到的一些問(wèn)題颁虐。
先看一段代碼
public abstract class BaseFragment extends Fragment {
private boolean isFirstVisible = true;
private boolean isFirstInvisible = true;
private boolean isViewCreated;
private boolean isUIVisible;
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
isViewCreated = true;
lazyLoad(); // 執(zhí)行懶加載,因?yàn)闊o(wú)法確定setUserVisibleHint和onViewCreated哪個(gè)方法先執(zhí)行蛮原,因此兩個(gè)方法里面都需要調(diào)用lazyLoad
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
isUIVisible = true; //當(dāng)前fragment可見(jiàn)
if (isFirstVisible) {
//如果是第一次可見(jiàn),則進(jìn)行懶加載
isFirstVisible = false;
lazyLoad();
} else {
//不是第一次可見(jiàn)另绩,則調(diào)用onUserVisible()
onUserVisible();
}
} else {
isUIVisible = false;
if (isFirstInvisible) {
isFirstInvisible = false;
//第一次不可見(jiàn)
onFirstUserInvisible();
} else {
//非第一次不可見(jiàn)
onUserInvisible();
}
}
}
private void lazyLoad() {
if (isViewCreated && isUIVisible) { //需要進(jìn)行雙重判斷儒陨,避免因?yàn)閟etUserVisibleHint先于onViewCreaetd調(diào)用時(shí),出現(xiàn)空指針
LogUtils.e( this.getClass().getSimpleName() + "lazyLoad");
// initViewsAndEvents();
onFirstUserVisible(); //進(jìn)行初次可見(jiàn)時(shí)的加載
}else {
LogUtils.e( this.getClass().getSimpleName() + ">>>>isViewCreated:" + isViewCreated + "------>>>>>isUIVisible:" + isUIVisible);
}
}
protected abstract void onFirstUserVisible();
protected abstract void onUserVisible();
protected abstract void onFirstUserInvisible();
protected abstract void onUserInvisible();
}
一般ViewPager+Fragment的時(shí)候笋籽,主要使用到了setUserVisibleHint()
方法進(jìn)行判斷Fragment是否可見(jiàn)蹦漠,來(lái)進(jìn)行懶加載處理。
但是
但是
但是
在某些場(chǎng)景中setUserVisibleHint()
竟然沒(méi)有執(zhí)行~~~~:在未使用Viewpager车海,而是自己通過(guò)FragmentTransaction 對(duì)Fragment進(jìn)行add hide show操作笛园,setUserVisibleHint()
方法沒(méi)有被調(diào)用。原因是hide()和show()方法調(diào)用時(shí),F(xiàn)ragment不走任何的生命周期研铆。
這時(shí)候突然發(fā)現(xiàn)另外一個(gè)Fragment方法onhiddenchanged()
闸度,該方法用于判斷fragment顯隱,正好切合hide show操作蚜印。
public abstract class LazyFragment extends BaseFragment {
public static final String TAG = LazyFragment.class.getSimpleName();
private boolean hasLoaded = false;
private boolean isCreated = false;
private boolean isVisibleToUser = false;
private View view;
@Override
protected void initViews(View view, @Nullable Bundle savedInstanceState) {
isCreated = true;
this.view = view;
lazyLoad(this.view, savedInstanceState);
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
this.isVisibleToUser = isVisibleToUser;//注:關(guān)鍵步驟
super.setUserVisibleHint(isVisibleToUser);
lazyLoad(view, null);
}
private void lazyLoad(View view, Bundle savedInstanceState) {
if (!isVisibleToUser || hasLoaded || !isCreated) {
return;
}
lazyInitView(view, savedInstanceState);
hasLoaded = true;//注:關(guān)鍵步驟,確保數(shù)據(jù)只加載一次
}
public abstract void lazyInitView(View view, Bundle savedInstanceState);
@Override
public void onDestroyView() {
super.onDestroyView();
isCreated = false;
hasLoaded = false;
}
}
然后對(duì)BaseFragment進(jìn)行進(jìn)一步封裝留量,應(yīng)對(duì)各種情況窄赋。
總結(jié)
onhiddenchanged()
用FragmentTransaction來(lái)控制fragment的hide和show時(shí),那么這個(gè)方法就會(huì)被調(diào)用楼熄。每當(dāng)你對(duì)某個(gè)Fragment使用hide或者是show的時(shí)候忆绰,那么這個(gè)Fragment就會(huì)自動(dòng)調(diào)用這個(gè)方法。
(使用情況:你自己去管理Fragment可岂,而不是用viewpager管理的時(shí)候)
setUserVisibleHin()
在使用viewpager的時(shí)候错敢,viewpager內(nèi)部有個(gè)提前緩存的機(jī)制(默認(rèn)是提前緩存一頁(yè)),比如你在看第一個(gè)Fragment的時(shí)候缕粹,隔壁的Fragment已經(jīng)創(chuàng)建好了稚茅,但此時(shí)的狀態(tài)卻是不可見(jiàn)的。
但是這時(shí)候Fragment不會(huì)去調(diào)用上面說(shuō)的onhiddenchanged方法平斩,只會(huì)調(diào)用setUserVisibleHint這個(gè)方法亚享。
參考
fragment 切換判斷界面是否可見(jiàn) setUserVisibleHint和onHiddenChanged使用場(chǎng)景