viewpager中多fragment及时加载

  Viewpager是我们经常使用的一个控件,它的使用这里就不多说了,我在这里说一下其中的一个效果,就是我们经常会看到在一些新闻类的 App中,使用viewpager来做各个频道的切换,在切换的时候,我们会发现,这些频道里面的数据,是在此频道为当前页的时候才进行加载,而不是一开始就加载的(这里说明一点,就是viewpager有预加载的功能),同时,当我们切换回来的时候,此页面并没有重新加载,数据还是原来的,就是说当切换回来的时候,数据没有进行再次请求。
对于这个效果,我用了一个比较笨,也是我现在唯一能想到的方法,来处理,在这里,做一个记录,如果你有好的方法,希望留言,大家共同进步。
      好了,下面我说一下我的方法:

     我们在使用viewpager的时候,最后都要使用一个setAdapter来绑定它的adpter。对于viewpager来说,它的最基本的adapter是pageAdapter。但是还有两个分别是FragmentPagerAdapter与FragmentStatePagerAdapter这两个从名字上就能看出来,主要是用来处理viewpager中如果是多个fragment的情况。它俩的区别在于是否将生成的fragment全放到内存中去。FragmentPagerAdapter是将fragment放到内存中去,而FragmentStatePagerAdapter则只保留当前的fragment。这里我们采用的是继承FragmentStatePagerAdapter来处理,它只需要完成两上方法就OK了,代码如下:

    

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. package com.example.cg.viewpagestatepageradapter;  
  2.   
  3. import android.support.v4.app.Fragment;  
  4. import android.support.v4.app.FragmentManager;  
  5. import android.support.v4.app.FragmentStatePagerAdapter;  
  6.   
  7. import java.util.List;  
  8.   
  9. /** 
  10.  * Created by cg on 2016/2/23. 
  11.  */  
  12. public class viewAdapter extends FragmentStatePagerAdapter {  
  13.   
  14.     private List<Fragment> list_fragment;  
  15.   
  16.     public viewAdapter(FragmentManager fm, List<Fragment> list_fragment) {  
  17.         super(fm);  
  18.         this.list_fragment = list_fragment;  
  19.     }  
  20.   
  21.     @Override  
  22.     public Fragment getItem(int position) {  
  23.         return list_fragment.get(position);  
  24.     }  
  25.   
  26.     @Override  
  27.     public int getCount() {  
  28.         return list_fragment.size();  
  29.     }  
  30.   
  31.     /** 
  32.      * 以触发销毁对象以及重建对象 
  33.      * @param object 
  34.      * @return 
  35.      */  
  36.     @Override  
  37.     public int getItemPosition(Object object) {  
  38.         return POSITION_NONE;  
  39.     }  
  40. }  


      从上面的代码来看,没什么特别之处,就是正常的一个adapter。确实如此,下面我们来看一下,fragment的代码,在这里你会发现有所不同。

 

     

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. package com.example.cg.viewpagestatepageradapter;  
  2.   
  3. import android.os.Bundle;  
  4. import android.support.annotation.Nullable;  
  5. import android.support.v4.app.Fragment;  
  6. import android.util.Log;  
  7. import android.view.LayoutInflater;  
  8. import android.view.View;  
  9. import android.view.ViewGroup;  
  10. import android.widget.ListView;  
  11. import android.widget.Toast;  
  12.   
  13. import com.example.cg.viewpagestatepageradapter.models.houseInfos;  
  14. import com.google.gson.Gson;  
  15. import com.google.gson.reflect.TypeToken;  
  16. import com.zhy.http.okhttp.OkHttpUtils;  
  17. import com.zhy.http.okhttp.callback.StringCallback;  
  18.   
  19. import java.util.ArrayList;  
  20. import java.util.List;  
  21.   
  22. import okhttp3.Call;  
  23.   
  24. /** 
  25.  * Created by cg on 2016/2/23. 
  26.  */  
  27. public class oneFragment extends Fragment {  
  28.   
  29.     private String Tag = "oneFragment";  
  30.   
  31.     private ListView lv_one;  
  32.     private List<houseInfos> list_h;  
  33.     private myAdatper mAdapter;  
  34.   
  35.     private myDialog dialog;  
  36.   
  37.     @Nullable  
  38.     @Override  
  39.     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {  
  40.   
  41.         Log.e(Tag,"onCreateView");  
  42.   
  43.   
  44.         View view = inflater.inflate(R.layout.fragment_one,container,false);  
  45.   
  46.         return view;  
  47.     }  
  48.   
  49.     @Override  
  50.     public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {  
  51.         super.onViewCreated(view, savedInstanceState);  
  52.   
  53.         Log.e(Tag, "onViewCreated");  
  54.   
  55.         lv_one = (ListView)view.findViewById(R.id.list_one);  
  56.   
  57.         if(list_h!=null)  
  58.         {  
  59.             initData();  
  60.         }  
  61.   
  62.     }  
  63.   
  64.   
  65.     @Override  
  66.     public void setUserVisibleHint(boolean isVisibleToUser) {  
  67.         super.setUserVisibleHint(isVisibleToUser);  
  68.         Log.e(Tag,"setUserVisibleHint:" + isVisibleToUser);  
  69.   
  70.         if(list_h!=null)  
  71.         {  
  72.             Log.e(Tag,"list_h=" + list_h.size());  
  73.         }  
  74.         if(isVisibleToUser && list_h == null)  
  75.         {  
  76.             initData();  
  77.         }  
  78.     }  
  79.   
  80.     public void initData()  
  81.     {  
  82.         dialog = new myDialog();  
  83.         dialog.show(getActivity().getFragmentManager(), "加载2");  
  84.   
  85.   
  86.         list_h = new ArrayList<houseInfos>();  
  87.   
  88.   
  89.   
  90.         String url = "http://bank.gxdgroup.com.cn/app/CommunityInfo.ashx";  
  91.         OkHttpUtils.get()  
  92.                 .url(url)  
  93.                 .addParams("flag","1")  
  94.                 .addParams("cityId","708")  
  95.                 .build()  
  96.                 .execute(new StringCallback() {  
  97.                     @Override  
  98.                     public void onError(Call call, Exception e) {  
  99.                         dialog.dismiss();  
  100.                         Toast.makeText(getActivity(), "有错误", Toast.LENGTH_SHORT).show();  
  101.                     }  
  102.   
  103.                     @Override  
  104.                     public void onResponse(String s) {  
  105.   
  106.                         list_h = new Gson().fromJson(s, new TypeToken<List<houseInfos>>() {  
  107.                         }.getType());  
  108.                         mAdapter = new myAdatper(getActivity(),R.layout.fragment_item,list_h);  
  109.                         lv_one.setAdapter(mAdapter);  
  110.                     }  
  111.   
  112.                 });  
  113.     }  
  114. }  


       这里大家注意到了,我们加载数据的地方是在setUserVisibleHint方法中,这个方法,是在createView方法之前就运行的。它里面的isVisibleToUser就是用来判断当前的fragment是否被用户可见,就是是否是当前的fragment.在这里,我们判断一下,如果它是可见的,我们才进行数据加载,如果不可见,则不进行加载。这样就解决了只有当前fragment加载数据的问题。
       好,我们再看一下主页

 

      

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. package com.example.cg.viewpagestatepageradapter;  
  2.   
  3. import android.os.Bundle;  
  4. import android.support.v4.app.Fragment;  
  5. import android.support.v7.app.AppCompatActivity;  
  6. import android.widget.Toast;  
  7.   
  8. import java.util.ArrayList;  
  9. import java.util.List;  
  10.   
  11. public class MainActivity extends AppCompatActivity {  
  12.   
  13.     private android.support.v4.view.ViewPager pager;  
  14.   
  15.     private List<Fragment> list_fragment;  
  16.     private viewAdapter vAdapter;  
  17.   
  18.     @Override  
  19.     protected void onCreate(Bundle savedInstanceState) {  
  20.         super.onCreate(savedInstanceState);  
  21.         setContentView(R.layout.activity_main);  
  22.   
  23.         initControls();  
  24.     }  
  25.   
  26.     /** 
  27.      * 初始化数据 
  28.      */  
  29.     private void initControls() {  
  30.         pager = (android.support.v4.view.ViewPager)findViewById(R.id.pager);  
  31.         //pager.setOffscreenPageLimit(2);  
  32.         list_fragment = new ArrayList<>();  
  33.   
  34.         oneFragment oFragment = new oneFragment();  
  35.         twoFragment tFragment = new twoFragment();  
  36.         threeFragment eFragment = new threeFragment();  
  37.   
  38.         list_fragment.add(oFragment);  
  39.         list_fragment.add(tFragment);  
  40.         list_fragment.add(eFragment);  
  41.   
  42.         vAdapter = new viewAdapter(getSupportFragmentManager(),list_fragment);  
  43.   
  44.         if(vAdapter==null)  
  45.         {  
  46.             Toast.makeText(this,"为什么是空呢!",Toast.LENGTH_SHORT).show();  
  47.         }else {  
  48.             pager.setAdapter(vAdapter);  
  49.         }  
  50.     }  
  51.   
  52.   
  53.   
  54. }  

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
    1.     这页没什么特别的,就是加载一下 viewpager,这里面的三个fragment代码基本上一样,就是取的数据不一样。我们来运行一下,你会发现,确实达到了我们要的效果,只有每页可见的时候才会加载,而且在第三页翻回第二页的时候,第二页的数据没有重新加载,而是保持了原有的状态,这样一看,好像很完美的解决了,我们的需求,可是.........当你从第二页翻向第一页的时候,你会发现第一页,是空白的,数据没有了.这是为什么呢,因为第一页被消除了,因为我们知道,viewpager默认的情况是预加载当前页的前,后各一个页面。所以当你到第三个页的时候,第一个页已经被消除了。  
    2. 这样就不是我们要的结果了,这怎么办,等一下,viewpager是默认加载当前页的前后各一个,如果我让他默认加前后各两个呢。我们来试试,  
    3. pager.setOffscreenPageLimit(2)  
    4. 这句代码,就是设置viewpager会预加载当前页面前后各几个页面的,因为我们一共就三个fragment,所以我就设置它为2,运行一下看一下效果,我们会发现,正好满足了我们的需求,每个页面只有在可见的时候才会加载数据,而且只在第一次加载数据,之后就不再加载数据了。  
    5. 这里你可能会说,这样不是还是在预加载了吗,是的,我们它让进行了预加载了,可是有一个问题是,我们加载的只是页面布局,而没有数据,这种情况下,对资源的占用就很小了。  
    6.   
    7. 问题:  
    8.     如果fragment很多的话,会产生什么后果,没有试过,但是想一想也会有问题。  
    9.   
    10.     总是感觉这个方法有点笨,而且适用于fragment数量少的加载数据的时候使用。  
posted @ 2016-11-24 20:35  天涯海角路  阅读(73)  评论(0)    收藏  举报