今天我們來聊一聊ViewPager+Fragment的懶加載冷尉。
參考資料:https://juejin.im/post/5adcb0e36fb9a07aa7673fbc
1.什么是懶加載涧团,為什么要用懶加載父腕?
如果我們的項(xiàng)目中使用了ViewPager+Framgment實(shí)現(xiàn)底部Tab可點(diǎn)可滑围小,那么我們都知道ViewPager有預(yù)加載功能蛤签,通過viewpager.setOffscreenPageLimit();來設(shè)置猬仁,不設(shè)置默認(rèn)加載上一個(gè)和下一個(gè)Fragment頁(yè)面事期,帶上本身也就是三個(gè)頁(yè)面(當(dāng)然如果你剛進(jìn)入就是首頁(yè),那么它會(huì)加載首頁(yè)和下一個(gè)頁(yè)面蒿偎,因?yàn)槭醉?yè)上面沒有頁(yè)面呀)朽们。預(yù)加載功能會(huì)暴露一個(gè)問題怀读,比如我剛進(jìn)入加載首頁(yè)的數(shù)據(jù),但是因?yàn)橛蓄A(yù)加載功能骑脱,那么就會(huì)執(zhí)行下一個(gè)Tab對(duì)應(yīng)的Fragmeng的生命周期菜枷,如果我下一個(gè)Tab頁(yè)數(shù)據(jù)量小還好,如果我有比較耗時(shí)的操作或者網(wǎng)絡(luò)請(qǐng)求叁丧,勢(shì)必會(huì)影響程序的性能啤誊,影響用戶的體驗(yàn)。那么我們要做的就是禁止ViewPager預(yù)加載或者提供一個(gè)只在Fragemnt可見的情況下拥娄,才去進(jìn)行耗時(shí)操作的方法蚊锹,只要Fragmeng可見我們就執(zhí)行該方法。
2.懶加載解決方式
2.1 嘗試設(shè)置setOffscreenPageLimit(失敗)
之前想既然setOffscreenPageLimit可以設(shè)置稚瘾,那我就將其設(shè)置為0牡昆,結(jié)果“然并卵”,查看源碼如下:
可以看到如果我們?cè)O(shè)置的值摊欠,小于DEFAULT_OFFSCREEN_PAGES這個(gè)常量值丢烘,那么就會(huì)被賦值為DEFAULT_OFFSCREEN_PAGES,那么我們看看DEFAULT_OFFSCREEN_PAGES值是多少:
也就是你設(shè)置的setOffscreenPageLimit要大于1才可以生效
2.2 試試懶加載
我們先來看看我們的頁(yè)面:
就是正常的viewpager+fragment些椒,每個(gè)頁(yè)面有一個(gè)TextView播瞳,可點(diǎn)可劃。三個(gè)Fragment依次是:HomeFragment,InvestFragment,UserFragment,
本次要用到的生命周期的方法是:
onCreatedView + onResume + onPause + onDestroyView本次要用到的非生命周期的方法是:setUserVisibleHint
簡(jiǎn)單介紹一下此方法:當(dāng)fragment被用戶可見時(shí)摊沉,setUserVisibleHint()會(huì)調(diào)用且傳入true值狐史,當(dāng)fragment不被用戶可見時(shí)痒给,setUserVisibleHint()則得到false值说墨,此方法先于生命周期方法執(zhí)行Fragment 主要的三個(gè)狀態(tài):第一次可見,每次可見苍柏,每次不可見
對(duì)于ViewPager+Fragment使用過程中的三種情況
(1) 使用 FragmentPagerAdapter 尼斧,F(xiàn)ragmentPagerStateAdapter不設(shè)置 setOffscreenPageLimit數(shù),采用默認(rèn)方式
(2)使用 FragmentPagerAdapter 试吁,F(xiàn)ragmentPagerStateAdapter設(shè)置 setOffscreenPageLimit數(shù)棺棵,設(shè)置為底部Tab總數(shù)
(3)使用 FragmentPagerAdapter ,F(xiàn)ragmentPagerStateAdapter進(jìn)入到其他頁(yè)面或者點(diǎn)擊Home鍵熄捍,返回到桌面烛恤。
其他注意的是:使用FragmentPagerAdapter 和FragmentPagerStateAdapter的區(qū)別在于FragmentPagerStateAdapter會(huì)在Fragment不可見的時(shí)候走 detach,而FragmentPagerAdapter不會(huì)余耽。
當(dāng)然我測(cè)試用的是FragmentPagerAdapter缚柏,我們先看一看正常滑動(dòng)碟贾,不設(shè)置setOffscreenPageLimit()币喧,F(xiàn)ragment生命周期是怎么走的轨域,先寫一個(gè)BaseLazyLoadFragment類繼承自Fragment.重寫我們剛才說的生命周期的方法,首頁(yè)等Fragment繼承BaseLazyLoadFragment打印生命周期(默認(rèn)進(jìn)來先加載首頁(yè)):
BaseLazyLoadFragment部分代碼如下
Fragment代碼如下
不設(shè)置setOffscreenPageLimit()杀餐,F(xiàn)ragmentPagerAdapter 結(jié)果如下
不設(shè)置setOffscreenPageLimit()干发,F(xiàn)ragmentPagerStateAdapter 結(jié)果如下:
這個(gè)結(jié)果我之前有過測(cè)試,直接告訴你們把區(qū)別是:FragmentPagerStateAdapter 會(huì)走一下兩個(gè)生命周期方法史翘,包括從切到Home頁(yè)面在返回這是一下走兩個(gè)生命周期方法枉长。
設(shè)置setOffscreenPageLimit()個(gè)數(shù)為總Tab數(shù),F(xiàn)ragmentPagerAdapter 和FragmentPagerStateAdapter結(jié)果一致琼讽,如下:
設(shè)置setOffscreenPageLimit為總數(shù)之后搀暑,一開始就加載了所有的Fragment
com.hxzk_bj_demo E/HomeFragment: isVisibleToUser------>false
com.hxzk_bj_demo E/InvestFragment:isVisibleToUser------>false
com.hxzk_bj_demo E/UserFragment: isVisibleToUser------>false
com.hxzk_bj_demo E/HomeFragment: isVisibleToUser------>true
com.hxzk_bj_demo E/HomeFragment: ------>onCreateView
com.hxzk_bj_demo E/HomeFragment: ------>onStart
com.hxzk_bj_demo E/HomeFragment: ------>onResume
com.hxzk_bj_demo E/InvestFragment: ------>onCreateView
com.hxzk_bj_demo E/UserFragment: ------>onCreateView
com.hxzk_bj_demo E/InvestFragment: ------>onStart
com.hxzk_bj_demo E/InvestFragment: ------>onResume
com.hxzk_bj_demo E/UserFragment: ------>onStart
com.hxzk_bj_demo E/UserFragment: ------>onResume
//第一個(gè)Fragment切換到第二個(gè)Fragment
com.hxzk_bj_demo E/HomeFragment: isVisibleToUser------>false
com.hxzk_bj_demo E/InvestFragment: isVisibleToUser------>true
//第二個(gè)Fragment切換到第三個(gè)Fragment
com.hxzk_bj_demo E/InvestFragment:isVisibleToUser------>false
com.hxzk_bj_demo E/UserFragment: isVisibleToUser------>true
//點(diǎn)擊Home
com.hxzk_bj_demo E/HomeFragment: ------>onPause
com.hxzk_bj_demo E/InvestFragment: ------>onPause
com.hxzk_bj_demo E/UserFragment: ------>onPause
//點(diǎn)擊Home后返回
com.hxzk_bj_demo E/HomeFragment: ------>onStart
com.hxzk_bj_demo E/InvestFragment: ------>onStart
com.hxzk_bj_demo E/UserFragment: ------>onStart
com.hxzk_bj_demo E/HomeFragment: ------>onResume
com.hxzk_bj_demo E/InvestFragment: ------>onResume
com.hxzk_bj_demo E/UserFragment: ------>onResume
沒啥的。
針對(duì)不設(shè)置setOffscreenPageLimit()跨琳,F(xiàn)ragmentPagerAdapter 結(jié)果我們分析一下:可以看到進(jìn)入到第一個(gè)Fragment的時(shí)候自点,也執(zhí)行了下一個(gè)Fragment的生命周期,執(zhí)行了不必要的操作脉让。那大家有沒有發(fā)現(xiàn)桂敛,如果那個(gè)Fragment的狀態(tài)為可見其setUserVisibleHint的值就為true,其余Fragment的值為false,那我們只需要判斷,如果setUserVisibleHint的值就為true即改Fragment為可見狀態(tài)溅潜,我們就執(zhí)行耗時(shí)操作术唬,其他Fragment為false,就不執(zhí)行網(wǎng)絡(luò)請(qǐng)求的操作唄。那我們寫一個(gè)公共的方法滚澜,注意此方法執(zhí)行粗仓,要放到onActivityCreate()之后,否則我請(qǐng)求回來的數(shù)據(jù)載體控件的Activity都沒有創(chuàng)建设捐,所以我要定義幾個(gè)變量來查看Fragment的狀態(tài),我們之前也說了Fragement有首次可見萝招,可見和不可見三種狀態(tài)蚂斤,代碼如下:
View rootView;
/**當(dāng)前Fragment是否首次可見,默認(rèn)是首次可見**/
private boolean mIsFirstVisible = true;
/**當(dāng)前Fragment的View是否已經(jīng)創(chuàng)建**/
private boolean isViewCreated = false;
/**當(dāng)前Fragment的可見狀態(tài)槐沼,一種當(dāng)前可見曙蒸,一種當(dāng)前不可見**/
private boolean currentVisibleState = false;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
LogUtil.e(getClass().getSimpleName(),"-----> onCreateView");
if(rootView == null){
rootView = inflater.inflate(getLayoutId(), container, false);
initView(rootView);
}
isViewCreated=true;//在onCreateView執(zhí)行完畢,將isViewCreated改為true;
return rootView;
}
不同生命周期變量值的變更及涉及的相關(guān)代碼:
- onStart
@Override
public void onStart() {
super.onStart();
LogUtil.e(getClass().getSimpleName(),"-----> onStart");
//isHidden()是Fragment是否處于隱藏狀態(tài)和isVisible()有區(qū)別
//getUserVisibleHint(),Fragement是否可見
if(!isHidden()&& getUserVisibleHint()){//如果Fragment沒有隱藏且可見
//執(zhí)行分發(fā)的方法,三種結(jié)果對(duì)應(yīng)自Fragment的三個(gè)回調(diào)岗钩,對(duì)應(yīng)的操作纽窟,F(xiàn)ragment首次加載,可見兼吓,不可見
disPatchFragment(true);
}
}
- onResume
@Override
public void onResume() {
super.onResume();
LogUtil.e(getClass().getSimpleName(),"-----> onResume");
if(!mIsFirstVisible){
//表示點(diǎn)擊home鍵又返回操作,設(shè)置可見狀態(tài)為ture
if(!isHidden()&& !getUserVisibleHint() && currentVisibleState){
disPatchFragment(true);
}
}
}
- onPause
@Override
public void onPause() {
super.onPause();
//表示點(diǎn)擊home鍵,原來可見的Fragment要走該方法臂港,更改Fragment的狀態(tài)為不可見
if(!isHidden()&& getUserVisibleHint()){
disPatchFragment(false);
}
}
- onDestroyView
@Override
public void onDestroyView() {
super.onDestroyView();
LogUtil.e(getClass().getSimpleName(),"-----> onStart");
//當(dāng) View 被銷毀的時(shí)候我們需要重新設(shè)置 isViewCreated mIsFirstVisible 的狀態(tài)
isViewCreated = false;
mIsFirstVisible = true;
}
- Fragment不同狀態(tài)對(duì)應(yīng)的回調(diào)方法
/**
*
* @param visible Fragment當(dāng)前是否可見,然后調(diào)用相關(guān)方法
*/
public void disPatchFragment(boolean visible){
currentVisibleState=visible;
if(visible){//Fragment可見
if(mIsFirstVisible){//可見又是第一次
mIsFirstVisible=false;//改變首次可見的狀態(tài)
onFragmentFirst();
}else{//可見但不是第一次
LogUtil.e(getClass().getSimpleName(),"可見");
}
}else {//不可見
LogUtil.e(getClass().getSimpleName(),"不可見");
}
};
//Fragemnet首次可見的方法
public void onFragmentFirst(){
LogUtil.e(getClass().getSimpleName(),"首次可見");
};
//Fragemnet可見的方法
public void onFragmentVisble(){//子Fragment調(diào)用次方法,執(zhí)行可見操作
LogUtil.e(getClass().getSimpleName(),"可見");
};
//Fragemnet不可見的方法
public void onFragmentInVisible(){
LogUtil.e(getClass().getSimpleName(),"不可見");
};
最后來一個(gè)總的代碼:
public abstract class BaseLazyLoadFragment extends android.support.v4.app.Fragment {
View rootView;
/**當(dāng)前Fragment是否首次可見趋艘,默認(rèn)是首次可見**/
private boolean mIsFirstVisible = true;
/**當(dāng)前Fragment的View是否已經(jīng)創(chuàng)建**/
private boolean isViewCreated = false;
/**當(dāng)前Fragment的可見狀態(tài)疲恢,一種當(dāng)前可見,一種當(dāng)前不可見**/
private boolean currentVisibleState = false;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
LogUtil.e(getClass().getSimpleName(),"-----> onCreateView");
if(rootView == null){
rootView = inflater.inflate(getLayoutId(), container, false);
initView(rootView);
}
isViewCreated=true;//在onCreateView執(zhí)行完畢瓷胧,將isViewCreated改為true;
return rootView;
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
LogUtil.e(getClass().getSimpleName(),"----->"+isVisibleToUser);
if (isViewCreated) {
if (isVisibleToUser && !currentVisibleState) {//Fragment可見且狀態(tài)不是可見(從一個(gè)Fragment切換到另外一個(gè)Fragment,后一個(gè)設(shè)置狀態(tài)為可見)
disPatchFragment(true);
} else if (!isVisibleToUser && currentVisibleState) {//Fragment不可見且狀態(tài)是可見(從一個(gè)Fragment切換到另外一個(gè)Fragment,前一個(gè)更改狀態(tài)為不可見)
disPatchFragment(false);
}
}
}
/**返回子Fragment的布局id**/
public abstract int getLayoutId();
/**初始化View的方法**/
public abstract void initView(View rootView);
@Override
public void onStart() {
super.onStart();
LogUtil.e(getClass().getSimpleName(),"-----> onStart");
//isHidden()是Fragment是否處于隱藏狀態(tài)和isVisible()有區(qū)別
//getUserVisibleHint(),Fragement是否可見
if(!isHidden()&& getUserVisibleHint()){//如果Fragment沒有隱藏且可見
//執(zhí)行分發(fā)的方法,三種結(jié)果對(duì)應(yīng)自Fragment的三個(gè)回調(diào)显拳,對(duì)應(yīng)的操作,F(xiàn)ragment首次加載搓萧,可見杂数,不可見
disPatchFragment(true);
}
}
@Override
public void onResume() {
super.onResume();
LogUtil.e(getClass().getSimpleName(),"-----> onResume");
if(!mIsFirstVisible){
//表示點(diǎn)擊home鍵又返回操作,設(shè)置可見狀態(tài)為ture
if(!isHidden()&& !getUserVisibleHint() && currentVisibleState){
disPatchFragment(true);
}
}
}
@Override
public void onPause() {
super.onPause();
//表示點(diǎn)擊home鍵,原來可見的Fragment要走該方法,更改Fragment的狀態(tài)為不可見
if(!isHidden()&& getUserVisibleHint()){
disPatchFragment(false);
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
LogUtil.e(getClass().getSimpleName(),"-----> onStart");
//當(dāng) View 被銷毀的時(shí)候我們需要重新設(shè)置 isViewCreated mIsFirstVisible 的狀態(tài)
isViewCreated = false;
mIsFirstVisible = true;
}
/**
*
* @param visible Fragment當(dāng)前是否可見瘸洛,然后調(diào)用相關(guān)方法
*/
public void disPatchFragment(boolean visible){
currentVisibleState=visible;
if(visible){//Fragment可見
if(mIsFirstVisible){//可見又是第一次
mIsFirstVisible=false;//改變首次可見的狀態(tài)
onFragmentFirst();
}else{//可見但不是第一次
LogUtil.e(getClass().getSimpleName(),"可見");
}
}else {//不可見
LogUtil.e(getClass().getSimpleName(),"不可見");
}
};
//Fragemnet首次可見的方法
public void onFragmentFirst(){
LogUtil.e(getClass().getSimpleName(),"首次可見");
};
//Fragemnet可見的方法
public void onFragmentVisble(){//子Fragment調(diào)用次方法揍移,執(zhí)行可見操作
LogUtil.e(getClass().getSimpleName(),"可見");
};
//Fragemnet不可見的方法
public void onFragmentInVisible(){
LogUtil.e(getClass().getSimpleName(),"不可見");
};
}
我們的Fragment只需要繼承BaseLazyLoadFragment,然后對(duì)應(yīng)調(diào)用首次可見方法反肋,再次可見方法那伐,不可見方法做相應(yīng)的操作就可以了。
懶加載進(jìn)階
我們上面說的是一層的ViewPager加Fragment石蔗,但大家也一定遇到過Fragemgt中又來了一層ViewPager+Fragment罕邀,如圖:
那這種的怎么辦呢?之前的方法還管用不养距,別急诉探,我們先看看其生命周期打印:
納尼棍厌,InvestFragment(投資)內(nèi)部第一個(gè)Tab,Invest_MineFragment竟然執(zhí)行了首次可見的方法肾胯,要知道此時(shí)的InvestFragmetn都沒有顯示。
針對(duì)此問題耘纱,我的解決方法是敬肚,先判斷父Fragment如果沒有顯示,那么不觸發(fā)我們定義的方法揣炕,代碼如下:
/**
*判斷多層嵌套的父Fragment是否顯示
*/
private boolean isParentFragmentInvisible() {
//獲取父Fragment的可見狀態(tài)
BaseLazyLoadFragment fragment = (BaseLazyLoadFragment) getParentFragment();
//如果兩個(gè)都滿足即父Fragment不為空且父Fragment不可見帘皿,返回true
return fragment != null && !fragment.getCurrentVisibleState();
}
private boolean getCurrentVisibleState() {
return currentVisibleState;
}
ok,我們?cè)谶\(yùn)行一下,打印如下:
感覺沒啥問題?
別急畸陡,還有剩余部分打印信息:
也就是我們還需要一個(gè)第一個(gè)子Fragment的狀態(tài)信息:解決思路如下:
由于父Fragment的執(zhí)行在子Fragment之前,所以虽填,當(dāng)我們?cè)诟?Fragment 分發(fā)完成自己的可見事件后丁恭,讓子 Fragment 再次調(diào)用自己的可見事件分發(fā)方法,這次我們讓 isParentFragmentVsible() 返回 false 斋日,可見狀態(tài)將會(huì)正確分發(fā)了牲览,有點(diǎn)類似于父類完成后,又調(diào)用方法刷新子類
恶守。
/**
*
* @param visible Fragment當(dāng)前是否可見第献,然后調(diào)用相關(guān)方法
*/
public void disPatchFragment(boolean visible){
String aa =getClass().getSimpleName();
//如果父Fragment不可見,則不向下分發(fā)給子Fragment
if(visible && isParentFragmentVsible())return;
currentVisibleState=visible;
if(visible){//Fragment可見
if(mIsFirstVisible){//可見又是第一次
mIsFirstVisible=false;//改變首次可見的狀態(tài)
onFragmentFirst();
}//可見但不是第一次
onFragmentVisble();
//可見狀態(tài)的時(shí)候內(nèi)層 fragment 生命周期晚于外層 所以在 onFragmentResume 后分發(fā)
dispatchChildFragmentVisibleState(true);
}else {//不可見
onFragmentInVisible();
dispatchChildFragmentVisibleState(false);
}
};
/**
* 父Fragment分發(fā)完成之后再次調(diào)用贡必,重新分發(fā)給子Fragment
* @param visible
*/
private void dispatchChildFragmentVisibleState(boolean visible) {
FragmentManager childFragmentManager = getChildFragmentManager();
@SuppressLint("RestrictedApi") List<Fragment> fragments = childFragmentManager.getFragments();
if(fragments != null){
if (!fragments.isEmpty()) {
for (Fragment child : fragments) {
if (child instanceof BaseLazyLoadFragment && !child.isHidden() && child.getUserVisibleHint()) {
((BaseLazyLoadFragment) child).disPatchFragment(visible);
}
}
}
}
}
這樣就ok了,然后我們點(diǎn)擊home鍵:
這又是什么問題庸毫,Invest_YourFragment為什么走了兩邊仔拟?
原因處在順序調(diào)用上,我剛才說了:父 Fragment總是優(yōu)先于子 Fragment飒赃,而對(duì)于不可見事件利花,內(nèi)部的 Fragment 生命周期總是先于外層 Fragment≡丶眩回到我們代碼里:父Fragment調(diào)用自身的 disPatchFragment方法分發(fā)了不可見事件,又會(huì)再次調(diào)用 dispatchChildFragmentVisibleState 炒事,導(dǎo)致子 Fragment 再次調(diào)用自己的 disPatchFragment再次調(diào)用了一次 不可見事件onFragmentInVisible,故產(chǎn)生了兩次蔫慧。
解決辦法就是我們之前定義的變量:currentVisibleState挠乳,如果當(dāng)前的 Fragment 要分發(fā)的狀態(tài)與 currentVisibleState 相同我們就沒有必要去做分發(fā)了。
代碼及添加位置如下:
``
``
最后附上總代碼姑躲,編寫Fragment時(shí)欲侮,只需要繼承該類,然后調(diào)用可見的方法就好了肋联。
public abstract class BaseLazyLoadFragment extends Fragment {
View rootView;
/**當(dāng)前Fragment是否首次可見威蕉,默認(rèn)是首次可見**/
private boolean mIsFirstVisible = true;
/**當(dāng)前Fragment的View是否已經(jīng)創(chuàng)建**/
private boolean isViewCreated = false;
/**當(dāng)前Fragment的可見狀態(tài),一種當(dāng)前可見橄仍,一種當(dāng)前不可見**/
private boolean currentVisibleState = false;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
LogUtil.e(getClass().getSimpleName(),"-----> onCreateView");
if(rootView == null){
rootView = inflater.inflate(getLayoutId(), container, false);
initView(rootView);
}
isViewCreated=true;//在onCreateView執(zhí)行完畢韧涨,將isViewCreated改為true;
return rootView;
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isViewCreated) {
if (isVisibleToUser && !currentVisibleState) {//Fragment可見且狀態(tài)不是可見(從一個(gè)Fragment切換到另外一個(gè)Fragment,后一個(gè)設(shè)置狀態(tài)為可見)
disPatchFragment(true);
} else if (!isVisibleToUser && currentVisibleState) {//Fragment不可見且狀態(tài)是可見(從一個(gè)Fragment切換到另外一個(gè)Fragment,前一個(gè)更改狀態(tài)為不可見)
disPatchFragment(false);
}
}
}
/**返回子Fragment的布局id**/
public abstract int getLayoutId();
/**初始化View的方法**/
public abstract void initView(View rootView);
@Override
public void onStart() {
super.onStart();
//isHidden()是Fragment是否處于隱藏狀態(tài)和isVisible()有區(qū)別
//getUserVisibleHint(),Fragement是否可見
if(!isHidden()&& getUserVisibleHint()){//如果Fragment沒有隱藏且可見
//執(zhí)行分發(fā)的方法,三種結(jié)果對(duì)應(yīng)自Fragment的三個(gè)回調(diào),對(duì)應(yīng)的操作侮繁,F(xiàn)ragment首次加載虑粥,可見,不可見
disPatchFragment(true);
}
}
@Override
public void onResume() {
super.onResume();
if(!mIsFirstVisible){
//表示點(diǎn)擊home鍵又返回操作,設(shè)置可見狀態(tài)為ture
if(!isHidden()&& !getUserVisibleHint() && currentVisibleState){
disPatchFragment(true);
}
}
}
@Override
public void onPause() {
super.onPause();
//表示點(diǎn)擊home鍵,原來可見的Fragment要走該方法宪哩,更改Fragment的狀態(tài)為不可見
if(!isHidden()&& getUserVisibleHint()){
disPatchFragment(false);
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
//當(dāng) View 被銷毀的時(shí)候我們需要重新設(shè)置 isViewCreated mIsFirstVisible 的狀態(tài)
isViewCreated = false;
mIsFirstVisible = true;
}
/**
*
* @param visible Fragment當(dāng)前是否可見娩贷,然后調(diào)用相關(guān)方法
*/
public void disPatchFragment(boolean visible){
String aa =getClass().getSimpleName();
//如果父Fragment不可見,則不向下分發(fā)給子Fragment
if(visible && isParentFragmentVsible())return;
// 如果當(dāng)前的 Fragment 要分發(fā)的狀態(tài)與 currentVisibleState 相同(都為false)我們就沒有必要去做分發(fā)了。
if (currentVisibleState == visible) {
return;
}
currentVisibleState=visible;
if(visible){//Fragment可見
if(mIsFirstVisible){//可見又是第一次
mIsFirstVisible=false;//改變首次可見的狀態(tài)
onFragmentFirst();
}//可見但不是第一次
onFragmentVisble();
//可見狀態(tài)的時(shí)候內(nèi)層 fragment 生命周期晚于外層 所以在 onFragmentResume 后分發(fā)
dispatchChildFragmentVisibleState(true);
}else {//不可見
onFragmentInVisible();
dispatchChildFragmentVisibleState(false);
}
};
/**
* 重新分發(fā)給子Fragment
* @param visible
*/
private void dispatchChildFragmentVisibleState(boolean visible) {
FragmentManager childFragmentManager = getChildFragmentManager();
@SuppressLint("RestrictedApi") List<Fragment> fragments = childFragmentManager.getFragments();
if(fragments != null){
if (!fragments.isEmpty()) {
for (Fragment child : fragments) {
if (child instanceof BaseLazyLoadFragment && !child.isHidden() && child.getUserVisibleHint()) {
((BaseLazyLoadFragment) child).disPatchFragment(visible);
}
}
}
}
}
//Fragemnet首次可見的方法
public void onFragmentFirst(){
LogUtil.e(getClass().getSimpleName(),"首次可見");
};
//Fragemnet可見的方法
public void onFragmentVisble(){//子Fragment調(diào)用次方法锁孟,執(zhí)行可見操作
LogUtil.e(getClass().getSimpleName(),"可見");
};
//Fragemnet不可見的方法
public void onFragmentInVisible(){
LogUtil.e(getClass().getSimpleName(),"不可見");
};
/**
*判斷多層嵌套的父Fragment是否顯示
*/
private boolean isParentFragmentVsible() {
BaseLazyLoadFragment fragment = (BaseLazyLoadFragment) getParentFragment();
return fragment != null && !fragment.getCurrentVisibleState();
}
private boolean getCurrentVisibleState() {
return currentVisibleState;
}
}
完畢彬祖!