android ViewPager+Fragment之懒加载

说说写这篇博客的背景吧,前两天去面试,问到一个问题说的是:比如我们首页,是有3个fragment构成的,并且要是实现作用可以滑,那么这个最好的选择就是ViewPager+fragment了,但是我们知道ViewPager+fragment是做预加载的,然而这种方法有一个坏处,当前页面和预加载页面都有大量的网络请求,可能就会比较慢,这样就会造成不好打体验。其实我们忽略的一个问题,Android的fragment里面已经帮我们提供了一个方法setUserVisibleHint。setUserVisibleHint()来显示与隐藏Fragment的。

我们看一下系统的代码:

 

[html] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. public void setUserVisibleHint(boolean isVisibleToUser) {  
  2.        if (!mUserVisibleHint && isVisibleToUser && mState STARTED) {  
  3.            mFragmentManager.performPendingDeferredStart(this);  
  4.        }  
  5.        mUserVisibleHint = isVisibleToUser;  
  6.        mDeferStart = !isVisibleToUser;  
  7.    }  


但是setUserVisibleHint优于onCreate调用,所以当onCreate调用完毕setUserVisibleHint就不会触发,这时需要在首个显示的fragment调用setUserVisibleHint方法。

 

所以我们在第一个Fragment创建成功之后,需要设置下下一个页面是否展示

 

[html] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. public void onActivityCreated(Bundle savedInstanceState) {  
  2.         // TODO Auto-generated method stub  
  3.         setUserVisibleHint(true);  
  4.         super.onActivityCreated(savedInstanceState);  
  5.     }  


为了方便我们使用我们可以继承fragment重写一下setUserVisibleHint方法。

 

 

[html] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. public abstract class BasePageFragment extends Fragment {  
  2.   
  3.     protected boolean isViewInitiated;  
  4.     protected boolean isVisibleToUser;  
  5.     protected boolean isDataInitiated;  
  6.   
  7.     @Override  
  8.     public void onCreate(Bundle savedInstanceState) {  
  9.         super.onCreate(savedInstanceState);  
  10.     }  
  11.   
  12.     @Override  
  13.     public void onActivityCreated(Bundle savedInstanceState) {  
  14.         super.onActivityCreated(savedInstanceState);  
  15.         isViewInitiated = true;  
  16.         prepareFetchData();  
  17.     }  
  18.   
  19.     @Override  
  20.     public void setUserVisibleHint(boolean isVisibleToUser) {  
  21.         super.setUserVisibleHint(isVisibleToUser);  
  22.         this.isVisibleToUser = isVisibleToUser;  
  23.         prepareFetchData();  
  24.     }  
  25.   
  26.     public abstract void fetchData();  
  27.   
  28.     public boolean prepareFetchData() {  
  29.         return prepareFetchData(false);  
  30.     }  
  31.   
  32.     public boolean prepareFetchData(boolean forceUpdate) {  
  33.         if (isVisibleToUser && isViewInitiated && (!isDataInitiated || forceUpdate)) {  
  34.             fetchData();  
  35.             isDataInitiated = true;  
  36.             return true;  
  37.         }  
  38.         return false;  
  39.     }  
  40.   
  41. }  


说下这里关于prepareFetchData的判断逻辑:当前UI可见,并且fragment已经初始化完毕,如果网络数据未加载,那么请求数据,或者需要强制刷新页面,那么再去请求页面数据,这样就达到了本文开始需要的要求。

 

用的话也听方便的:

 

[html] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. public class PageFragment extends BasePageFragment {  
  2.   
  3.     public static PageFragment newInstance(String title){  
  4.         PageFragment fragment = new PageFragment();  
  5.         Bundle args = new Bundle();  
  6.         args.putString("key_fragment_title", title);  
  7.         fragment.setArguments(args);  
  8.         return fragment;  
  9.     }  
  10.   
  11.     private String title;  
  12.     private TextView tv;  
  13.   
  14.     @Override  
  15.     public void onCreate(Bundle savedInstanceState) {  
  16.         super.onCreate(savedInstanceState);  
  17.         title = getArguments().getString("key_fragment_title");  
  18.         Trace.d(title + ":onCreate");  
  19.     }  
  20.   
  21.     @Override  
  22.     public void onResume() {  
  23.         super.onResume();  
  24.         Trace.d(title + ":onResume");  
  25.     }  
  26.   
  27.   
  28.     @Override  
  29.     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {  
  30.         Trace.d(title + ":onCreateView");  
  31.         tv = new TextView(getActivity());  
  32.         return tv;  
  33.     }  
  34.   
  35.     @Override  
  36.     public void fetchData() {<pre code_snippet_id="1723966" snippet_file_name="blog_20160621_4_911600" name="code" class="html">    //这里是网络异步请求返回  
[html] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. tv.setText(title); }}  

}

 

通过setOffscreenPageLimit进行Fragment缓存

 

[html] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. public void setOffscreenPageLimit(int limit) {  
  2.          
  3.  if (limit DEFAULT_OFFSCREEN_PAGES) {  
  4.             Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " +  
  5.                     DEFAULT_OFFSCREEN_PAGES);  
  6.             limit = DEFAULT_OFFSCREEN_PAGES;  
  7.         }  
  8.         if (limit != mOffscreenPageLimit) {  
  9.             mOffscreenPageLimit = limit;  
  10.             populate();  
  11.         }  
  12.     }  



 



好了,最近面试面到的比较坑的问题还蛮多(比如Intent底层实现,Looper底层算法,Ams等),借此机会好好看下源码,欢迎留言。

posted @ 2017-04-21 22:46  天涯海角路  阅读(154)  评论(0)    收藏  举报