Fragment的setUserVisibleHint方法實現懶加載,但setUserVisibleHint 不起作用?


      我們在做應用開發的時候,一個Activity里面可能會以viewpager(或其他容器)與多個Fragment來組合使用,而如果每個fragment都需要去加載數據,或從本地加載,或從網絡加載,那么在這個activity剛創建的時候就變成需要初始化大量資源。這樣的結果,我們當然不會滿意。那么,能不能做到當切換到這個fragment的時候,它才去初始化呢?
答案就在Fragment里的setUserVisibleHint這個方法里。請看關於Fragment里這個方法的API文檔:

該方法用於告訴系統,這個Fragment的UI是否是可見的。所以我們只需要繼承Fragment並重寫該方法,即可實現在fragment可見時才進行數據加載操作,即Fragment的懶加載。根據網友們提供的方法,代碼如下(本人稍作修改了下):

 1 import android.os.Bundle;
 2 import android.support.v4.app.Fragment;
 3 
 4 /**
 5  * Author: wangjie
 6  * Email: tiantian.china.2@gmail.com
 7  * Date: 1/23/15.
 8  */
 9 public abstract class BaseLazyFragment extends Fragment {
10     private static final String TAG = BaseLazyFragment.class.getSimpleName();
11     private boolean isPrepared;
12 
13     @Override
14     public void onActivityCreated(Bundle savedInstanceState) {
15         super.onActivityCreated(savedInstanceState);
16         initPrepare();
17     }
18 
19 
20     /**
21      * 第一次onResume中的調用onUserVisible避免操作與onFirstUserVisible操作重復
22      */
23     private boolean isFirstResume = true;
24 
25     @Override
26     public void onResume() {
27         super.onResume();
28         if (isFirstResume) {
29             isFirstResume = false;
30             return;
31         }
32         if (getUserVisibleHint()) {
33             onUserVisible();
34         }
35     }
36 
37     @Override
38     public void onPause() {
39         super.onPause();
40         if (getUserVisibleHint()) {
41             onUserInvisible();
42         }
43     }
44 
45     private boolean isFirstVisible = true;
46     private boolean isFirstInvisible = true;
47 
48     @Override
49     public void setUserVisibleHint(boolean isVisibleToUser) {
50         super.setUserVisibleHint(isVisibleToUser);
51         if (isVisibleToUser) {
52             if (isFirstVisible) {
53                 isFirstVisible = false;
54                 initPrepare();
55             } else {
56                 onUserVisible();
57             }
58         } else {
59             if (isFirstInvisible) {
60                 isFirstInvisible = false;
61                 onFirstUserInvisible();
62             } else {
63                 onUserInvisible();
64             }
65         }
66     }
67 
68     public synchronized void initPrepare() {
69         if (isPrepared) {
70             onFirstUserVisible();
71         } else {
72             isPrepared = true;
73         }
74     }
75 
76     /**
77      * 第一次fragment可見(進行初始化工作)
78      */
79     public abstract void onFirstUserVisible();
80 
81     /**
82      * fragment可見(切換回來或者onResume)
83      */
84     public abstract void onUserVisible();
85 
86     /**
87      * 第一次fragment不可見(不建議在此處理事件)
88      */
89     public abstract void onFirstUserInvisible();
90 
91     /**
92      * fragment不可見(切換掉或者onPause)
93      */
94     public abstract void onUserInvisible();
95 
96 }

如上代碼,使用setUserVisibleHint方法作為回調的依據,
暴露出來讓子類使用的新的生命周期方法為:


- onFirstUserVisible();
第一次fragment可見(進行初始化工作)


- onUserVisible();
fragment可見(切換回來或者onResume)


- onFirstUserInvisible();
第一次fragment不可見(不建議在此處理事件)


- onUserInvisible();
fragment不可見(切換掉或者onPause)

據說具體的效果是:

1. 首先加載ViewPager,回調FragmentA(第一個默認呈現的Fragment)的onFirstUserVisible(),可以在這里進行FragmentA的初始化工作,其他Fragment保持不變。

2. 用戶從FragmentA滑動到FragmentB,回調FragmentA的onUserInvisible()、FragmentB的onFirstUserVisible()(因為第一次切換到FragmentB,可以在這里進行初始化工作)。

3. 用戶從FragmentB滑動到FragmentC,回調FragmentB的onUserInvisible()、FragmentC的onFirstUserVisible()(因為第一次切換到FragmentC,可以在這里進行初始化工作)。

4. 用戶從FragmentC滑動到FragmentB,回調FragmentC的onUserInvisible()、FragmentB的onUserVisible()(因為FragmentB之前已經被加載過)。

5. 因為到此為止,suoyou的Fragment都已經被加載過了,所以以后這3個Fragment互相任意切換,只會回調原來Fragment的onUserInvisible()和切換后的Fragment的onUserVisible()。

6. 用戶處於FragmentB,關閉手機屏幕,回調FragmentB的onUserInvisible()。

7. 用戶處於FragmentB,手機屏幕處關閉狀態,然后開啟手機屏幕解鎖,只回調FragmentB的onUserVisible()。

可我TM無論怎么調試都沒這個效果好嗎,TMD setUserVisibleHint()就是不調用,不執行!!!

問度娘TMD都有是千篇一律的是使用fragment的setUserVisibleHint()方法實現懶加載,使用fragment的setuservisiblehint ()方法實現懶加載,使用fragment的setUserVisibleHint()方法實現懶加載;我去!!!我都快崩潰了好嗎。

無果只能求助國外的網友了,豎上梯子問google(搜索 fragment setuservisiblehint not called)我的男神去了,打開第一條搜索結果,這個結果是我的另一個男神:,這就是我正想要的,國外的網友給的答案如下:

答案大致意思是:需要 FragmentPagerAdapter 顯示的對setUserVisibleHint()方法的調用,查看自己的adapter原來是繼承的PagerAdapter 而不是FragmentPagerAdapter,於是果斷重新生成一個繼承 FragmentPagerAdapter 的 adapter,

代碼如下:

 1  
 3 import android.support.v4.app.Fragment;
 4 import android.support.v4.app.FragmentManager;
 5 import android.support.v4.app.FragmentPagerAdapter;
 6 
 7 import java.util.ArrayList;
 8 import java.util.List;
 9 
10 public class SimpleFragmentPagerAdapter  extends FragmentPagerAdapter {
11     private List<Fragment> listFragments;
12     private List<String> mTitleList = new ArrayList<>();//頁卡標題集合
13 
14     public SimpleFragmentPagerAdapter(FragmentManager fm,
15                                   List<Fragment> al,
16                                   List<String> titleList) {
17         super(fm);
18         listFragments = al;
19         mTitleList =  titleList;
20     }
21 
22     public SimpleFragmentPagerAdapter(FragmentManager fm) {
23         super(fm);
24     }
25 
26     @Override
27     public Fragment getItem(int position) {
28         return listFragments.get(position);
29     }
30 
31     @Override
32     public int getCount() {
33         return listFragments.size();
34     }
35 
36     @Override
37     public int getItemPosition(Object object) {
38         return super.getItemPosition(object);
39     }
40 
41     @Override
42     public CharSequence getPageTitle(int position) {
43         return mTitleList.get(position);//頁卡標題
44     }
45 }

然后將該adapter賦予Viewpager ,經調試成功了,setUserVisibleHint()方法終於起作用了,懶加載也有了。

 項目源碼:https://github.com/Leevey/LazyLoadFragment

參考文獻:

實現類似微信的延遲加載的Fragment——LazyFragment

stackoverflow:Is Fragment.setUserVisibleHint() called by the android System?

FragmentPagerAdapter.java的源碼

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM