RecyclerView使用 及 滑动时加载图片优化方案


简述

本篇博文主要给大家分享关于RecyclerView控件的使用及通过继承RecyclerView来实现滑动时加载图片的优化方案,也同样能解决防止图片乱序的问题,之前有在网上有看到大神对Android中ListView异步加载图片乱序问题进行过分析,并深入剖析原理后分别给出了3种对应的解决方案:一 、使用findViewWithTag。二、使用弱引用关联。三、使用Volley框架提供的NetworkImageView。

看了之后思索了很久,后来才想到,哦,原来自己也一直这么在用。也算是一种解决方案吧,虽然不是从问题的根本进行处理,但根据实际业务需要,也同样能合理的解决。如以下两种方案:

  • 1、控制线程数量 + 数据分页加载
  • 2、重写onScrollStateChanged方法

这个我们后面再谈,下面先来看看RecyclerView控件的使用及我们为什么选择使用它。

RecyclerView的使用

RecyclerView 位于package android.support.v7.widget; 包下,直接继承了android.view.ViewGroup,是Android中新添加的一个用来取代ListView的滑动控件,其灵活性与可替代性比ListView更优秀,运行原理与ListView类似,都是通过维护少量的View可展示大量的数据集。

总结其优点:

  • 一、标准化了ViewHolder,使用Adapter适配器时,面向ViewHolder而不是单纯的View,直接把ViewHolder的实现封装起来,用户只要实现自己的ViewHolder就可以了,该组件会自动帮你回收并复用每一个item。不但变得更精简,也变得更加容易使用,而且更容易组合设计出自己需要的滑动布局。
  • 二、将Layout抽象成了一个LayoutManager,RecyclerView不负责子View的布局,而是通过使用LayoutManager来实现不同的布局效果,如使用LinearLayoutManager来指定方向,其默认是垂直,也可以设置为水平,当然你也可以自己来定义。

我们来看看官方给出的示例:

1.MyActivity.java

  public class MyActivity extends Activity {  private RecyclerView mRecyclerView;  private RecyclerView.Adapter mAdapter;  private RecyclerView.LayoutManager mLayoutManager;  @Override  protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.my_activity);  mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);  // improve performance if you know that changes in content do not change the size of the RecyclerView  //如果确定每个item的内容不会改变RecyclerView的大小,设置这个选项可以提高性能mRecyclerView.setHasFixedSize(true);  // use a linear layout manager  //创建默认的线性LayoutManagermLayoutManager = new LinearLayoutManager(this);  mRecyclerView.setLayoutManager(mLayoutManager);  // specify an adapter (see also next example)  //设置AdaptermAdapter = new MyAdapter(myDataset);  mRecyclerView.setAdapter(mAdapter);  }  ...
}

LayoutManager:用来确定每一个item如何进行排列摆放,何时展示和隐藏。提供默认的动画效果,你也可以定义你自己的LayoutManager和添加删除动画。在回收或重用一个View时,LayoutManager会向适配器请求新的数据来替换旧的数据,这种机制避免了创建过多的View和频繁的调用findViewById方法。

2.MyAdapter

  public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {  private String[] mDataset;  // Provide a reference to the type of views that you are using (custom viewholder)  //自定义的ViewHolder,持有每个Item的的所有界面元素public static class ViewHolder extends RecyclerView.ViewHolder {  public TextView mTextView;  public ViewHolder(TextView v) {  super(v);  mTextView = v;  }  }  // Provide a suitable constructor (depends on the kind of dataset)  public MyAdapter(String[] myDataset) {  mDataset = myDataset;  }  // Create new views (invoked by the layout manager)  //创建新View,被LayoutManager调用@Override  public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,  int viewType) {  // create a new view  View v = LayoutInflater.from(parent.getContext())  .inflate(R.layout.my_text_view, parent, false);  // set the view's size, margins, paddings and layout parameters  ...  ViewHolder vh = new ViewHolder(v);  return vh;  }  // Replace the contents of a view (invoked by the layout manager)  //将数据与界面进行绑定@Override  public void onBindViewHolder(ViewHolder holder, int position) {  // - get element from your dataset at this position  // - replace the contents of the view with that element  holder.mTextView.setText(mDataset[position]);  }  // Return the size of your dataset (invoked by the layout manager)  //这个就不解释了@Override  public int getItemCount() {  return mDataset.length;  }
}

Adapter:在使用RecyclerView之前,你需要一个继承自RecyclerView.Adapter的适配器,作用是将数据与每一个item的界面进行绑定。

3.XML布局

<!-- A RecyclerView with some commonly used attributes -->
<android.support.v7.widget.RecyclerView  android:id="@+id/my_recycler_view"  android:scrollbars="vertical"  android:layout_width="match_parent"  android:layout_height="match_parent"/>

注: recyclerview No adapter attached; skipping layout 若出现该错误,是由于跳过了布局,没有Adapter与之对接的原因。

附:

①设置为横向的List:

mLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);

②设置Grid布局列表,声明LayoutManager为GridLayoutManager即可:

mLayoutManager = new GridLayoutManager(context,columNum);
mRecyclerView.setLayoutManager(mLayoutManager);

③瀑布流布局

//使用StaggeredGridLayoutManager

从上述例子可以看出,RecyclerView的用法并不复杂,反而更灵活好用,它将数据、排列方式、数据的展示方式都分割开来,自定义的形式也非常多,非常灵活。下方共享一个开源示例,且解决了ScrollView嵌套RecyclerView无法显示的问题:

        

     

下载链接:http://download.csdn.net/detail/gao_chun/9124221

滑动时图片优化方案描述

1、控制线程数量 + 数据分页加载

我们在使用滑动控件呈现图片数据时,显然都会在getView方法里创建新的线程去异步加载图片,不可能有一百条或上千条数据一口气全部塞过来吧(当然你要这么干也是可以的),那么根据项目需求必然会进行分页加载,咱一页显示的item条数也别太夸张就好。而且,当我们点击屏幕快速向下滑动时,每个Item都会调用getView一次,必然会创建出很多线程去加载图片的URL资源,控制好线程的数量,加个线程池就非常有必要了。为了避免OOM导致FC,注意图片需要缓存,因为从内存中读取图片资源是非常快的。

2、重写onScrollStateChanged方法

这种方案用的也很普遍,相信只要细心观察,就会发现类似微博、Facebook、或者一些图片壁纸类的APP,在滑动时未加载的图片是不会立刻加载呈现的,只有当滑动停止后才会加载,这里需要注意一点的是,只加载当前屏幕内的图片。这么一说可能有童鞋就明白了。我们可以通过继承RecyclerView去自定义一个滑动控件,通过继承OnScrollListener后重写其 onScrolled方法 和 onScrollStateChanged 等方法来做相应处理。

例如:

private class AutoLoadScrollListener extends OnScrollListener {   //......public void onScrollStateChanged(RecyclerView recyclerView, int newState){}}

我们通过 extends OnScrollListener 并且 @Override 其 onScrollStateChanged 方法,通过判断state来处理,此处对其滚动的状态newState做一个说明,方面大家了解学习,分别有3个状态,即 0 - 1 - 2:

状态为0时:当前屏幕停止滚动;

状态为1时:屏幕在滚动 且 用户仍在触碰或手指还在屏幕上;

状态为2时:随用户的操作,屏幕上产生的惯性滑动;


实现

我们就不自己去写那些异步加载图片,缓存啥的代码块了,简单明了,直接使用ImageLoader就可以。下面通过实例讲解该功能的实现,老规矩,先来效果图:

              

先来瞄瞄activity_main.xml布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:fitsSystemWindows="true"android:orientation="vertical"><RelativeLayoutandroid:id="@+id/layout_titlebar"android:layout_width="match_parent"android:layout_height="48dp"android:background="#00F1A0"><TextViewandroid:textSize="16dp"android:id="@+id/text_title"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"android:text="好慌~"android:textColor="@android:color/white" /></RelativeLayout><FrameLayoutandroid:id="@+id/frame_container"android:layout_width="match_parent"android:layout_height="match_parent" /></LinearLayout>

很简单,用了一个Fragment而已,再来看看主Fragment的布局:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@android:color/white"><android.support.v4.widget.SwipeRefreshLayoutandroid:id="@+id/swipeRefreshLayout"android:layout_width="match_parent"android:layout_height="match_parent"><org.gaochun.view.AutoLoadRecyclerViewandroid:id="@+id/recycler_view"android:layout_width="match_parent"android:layout_height="match_parent"android:scrollbars="vertical" /></android.support.v4.widget.SwipeRefreshLayout></FrameLayout>

我们使用了 SwipeRefreshLayout 中包裹了自定义的 AutoLoadRecyclerView,关于SwipeRefreshLayout 控件的使用,大家可以自行百度,这里就不多说了。有盆友可能会说,挖槽,好慌~ ,这测试图哪来的,貌似还挺清晰的哇,好吧,只能帮你到这了:

package org.gaochun.myapplication;import java.util.ArrayList;
import java.util.List;/*** Created by gao_chun on 2015/9/18.*/
public class ImageUrl {public static List<String> imageList(){List<String> mUrls = new ArrayList<String>();mUrls.add("http://e.hiphotos.baidu.com/image/pic/item/a1ec08fa513d2697e542494057fbb2fb4316d81e.jpg");mUrls.add("http://c.hiphotos.baidu.com/image/pic/item/30adcbef76094b36de8a2fe5a1cc7cd98d109d99.jpg");mUrls.add("http://h.hiphotos.baidu.com/image/pic/item/7c1ed21b0ef41bd5f2c2a9e953da81cb39db3d1d.jpg");mUrls.add("http://g.hiphotos.baidu.com/image/pic/item/55e736d12f2eb938d5277fd5d0628535e5dd6f4a.jpg");mUrls.add("http://e.hiphotos.baidu.com/image/pic/item/4e4a20a4462309f7e41f5cfe760e0cf3d6cad6ee.jpg");mUrls.add("http://b.hiphotos.baidu.com/image/pic/item/9d82d158ccbf6c81b94575cfb93eb13533fa40a2.jpg");mUrls.add("http://e.hiphotos.baidu.com/image/pic/item/4bed2e738bd4b31c1badd5a685d6277f9e2ff81e.jpg");mUrls.add("http://www.huabian.com/uploadfile/2014/1202/20141202025659854.jpg");mUrls.add("http://www.huabian.com/uploadfile/2014/1202/20141202025700989.jpg");mUrls.add("http://g.hiphotos.baidu.com/image/pic/item/0d338744ebf81a4c87a3add4d52a6059252da61e.jpg");mUrls.add("http://a.hiphotos.baidu.com/image/pic/item/f2deb48f8c5494ee5080c8142ff5e0fe99257e19.jpg");mUrls.add("http://f.hiphotos.baidu.com/image/pic/item/4034970a304e251f503521f5a586c9177e3e53f9.jpg");mUrls.add("http://b.hiphotos.baidu.com/image/pic/item/279759ee3d6d55fbb3586c0168224f4a20a4dd7e.jpg");mUrls.add("http://img2.xkhouse.com/bbs/hfhouse/data/attachment/forum/corebbs/2009-11/2009113011534566298.jpg");mUrls.add("http://a.hiphotos.baidu.com/image/pic/item/e824b899a9014c087eb617650e7b02087af4f464.jpg");mUrls.add("http://c.hiphotos.baidu.com/image/pic/item/9c16fdfaaf51f3de1e296fa390eef01f3b29795a.jpg");mUrls.add("http://d.hiphotos.baidu.com/image/pic/item/b58f8c5494eef01f119945cbe2fe9925bc317d2a.jpg");mUrls.add("http://h.hiphotos.baidu.com/image/pic/item/902397dda144ad340668b847d4a20cf430ad851e.jpg");mUrls.add("http://b.hiphotos.baidu.com/image/pic/item/359b033b5bb5c9ea5c0e3c23d139b6003bf3b374.jpg");mUrls.add("http://a.hiphotos.baidu.com/image/pic/item/8d5494eef01f3a292d2472199d25bc315d607c7c.jpg");mUrls.add("http://b.hiphotos.baidu.com/image/pic/item/e824b899a9014c08878b2c4c0e7b02087af4f4a3.jpg");mUrls.add("http://g.hiphotos.baidu.com/image/pic/item/6d81800a19d8bc3e770bd00d868ba61ea9d345f2.jpg");return mUrls;}
}

下面来看看主要的类AutoLoadRecyclerView,其实这个类也很简单:

public class AutoLoadRecyclerView extends RecyclerView implements LoadFinishCallBack {private onLoadMoreListener loadMoreListener;   //加载更多回调private boolean isLoadingMore;                  //是否加载更多public AutoLoadRecyclerView(Context context) {this(context, null);}public AutoLoadRecyclerView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public AutoLoadRecyclerView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);isLoadingMore = false;   //默认无需加载更多setOnScrollListener(new AutoLoadScrollListener(null, true, true));}/*** 配置显示图片,需要设置这几个参数,快速滑动时,暂停图片加载** @param imageLoader  ImageLoader实例对象* @param pauseOnScroll* @param pauseOnFling*/public void setOnPauseListenerParams(ImageLoader imageLoader, boolean pauseOnScroll, boolean pauseOnFling) {setOnScrollListener(new AutoLoadScrollListener(imageLoader, pauseOnScroll, pauseOnFling));}public void setLoadMoreListener(onLoadMoreListener loadMoreListener) {this.loadMoreListener = loadMoreListener;}@Overridepublic void loadFinish(Object obj) {isLoadingMore = false;}//加载更多的回调接口public interface onLoadMoreListener {void loadMore();}/*** 滑动自动加载监听器*/private class AutoLoadScrollListener extends OnScrollListener {private ImageLoader imageLoader;private final boolean pauseOnScroll;private final boolean pauseOnFling;public AutoLoadScrollListener(ImageLoader imageLoader, boolean pauseOnScroll, boolean pauseOnFling) {super();this.pauseOnScroll = pauseOnScroll;this.pauseOnFling = pauseOnFling;this.imageLoader = imageLoader;}@Overridepublic void onScrolled(RecyclerView recyclerView, int dx, int dy) {super.onScrolled(recyclerView, dx, dy);//由于GridLayoutManager是LinearLayoutManager子类,所以也适用if (getLayoutManager() instanceof LinearLayoutManager) {int lastVisibleItem = ((LinearLayoutManager) getLayoutManager()).findLastVisibleItemPosition();int totalItemCount = AutoLoadRecyclerView.this.getAdapter().getItemCount();//有回调接口,且不是加载状态,且计算后剩下2个item,且处于向下滑动,则自动加载if (loadMoreListener != null && !isLoadingMore && lastVisibleItem >= totalItemCount -2 && dy > 0) {loadMoreListener.loadMore();isLoadingMore = true;}}}//当屏幕停止滚动时为0;当屏幕滚动且用户使用的触碰或手指还在屏幕上时为1;由于用户的操作,屏幕产生惯性滑动时为2@Overridepublic void onScrollStateChanged(RecyclerView recyclerView, int newState) {//根据newState状态做处理if (imageLoader != null) {switch (newState) {case 0:imageLoader.resume();break;case 1:if (pauseOnScroll) {imageLoader.pause();} else {imageLoader.resume();}break;case 2:if (pauseOnFling) {imageLoader.pause();} else {imageLoader.resume();}break;}}}}

也就是说,我们通过定义了一个 setOnPauseListenerParams 方法去设置滑动监听事件setOnScrollListener,并通过定义内部类AutoLoadScrollListener去@Override相关方法并做相应的处理。

下载链接:http://download.csdn.net/detail/gao_chun/9124659

【转载注明gao_chun的Blog:http://blog.csdn.net/gao_chun/article/details/48550117】

RecyclerView使用 及 滑动时加载图片优化方案相关推荐

  1. Android RecyclerView使用 及 滑动时加载图片优化方案

    1.控制线程数量 + 数据分页加载2.重写onScrollStateChanged方法 这个我们后面再谈,下面先来看看RecyclerView控件的使用及我们为什么选择使用它 RecyclerView ...

  2. RecyclerView使用 及 滑动时加载图片优化方案,GitHub上标星13k的《Android面试突击版》

    setContentView(R.layout.my_activity); mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_v ...

  3. RecyclerView使用 及 滑动时加载图片优化方案,android应用程序开发语言

    // Provide a reference to the type of views that you are using (custom viewholder) //自定义的ViewHolder, ...

  4. android listview 只加载显示的图片大小,Android ListView只加载当前屏幕内的图片(解决list滑动时加载卡顿)...

    最近在做ListView分页显示,其中包括图片 和文字(先下载解析文字内容,再异步加载图片)发现每次点击下一页后,文字内容加载完毕,马上向下滑动,由于这时后台在用线程池异步下载图片,我每页有20条,也 ...

  5. Android之 ListView滑动时不加载图片

    listview加载图片优化的功能, 在我们使用新浪微博的时候,细心的同学一定发现了,在滑动的过程中,图片是没有被加载的, 而是在滑动停止时,才加载图片了. 我们今天就做一个这样的效果吧. 我们先考虑 ...

  6. Unity大场景数据加载及优化方案

    前段时间,有几个虚拟仿真公司跟我请教关于大地形的加载优化问题,它们使用的引擎都是自己研发的,引擎对于开发者来说,大同小异,它们的基本构造是一样的,关键是在于解决问题的方法,正是基于这个前提写了这个课程 ...

  7. LIstview滑动时不加载图片,停止时加载!

    //参照 http://blog.csdn.net/yy1300326388/article/details/45153813 public class CarWashDistanceAdapter ...

  8. SDWebImage的坑,无网络时加载图片失败,有网络后依然无法加载显示的问题

    网上查找得知 当SDWebImage 在加载图片的时候 我用的是- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *) ...

  9. 游戏UI动态加载图片优化

    说到UI优化,很多人对其并不以为意,UI的制作无非使用UGUI或者NGUI.UI优化主要是针对图集,还有一些依赖项的优化,针对的是内存优化,上面这些都是关于静态UI的优化,这个是作为程序员都要经历的阶 ...

最新文章

  1. controller不跳转页面的几个原因_狗狗为什么不睡觉?是这几个原因
  2. CF939E:Maximize! ——题解
  3. matlab列优先与高维矩阵重构 及 CNN 逐层可视化 on Matlab
  4. C++最大数的幂 largest power实现算法(附完整源码)
  5. 网站制作中常用的一些网页布局
  6. 【Elasticsearch】数据预加载
  7. android美颜功能吗,Android美颜sdk接入之前需要知道这些知识吗
  8. jQuery基础--选择器
  9. radius服务器mac_连如何抵御MAC攻击都不知道 过年还如何抵御三姑六婆的魔法攻击...
  10. Atitit prj tek dfkt 项目常见技术难点目录第一章 开发效率 2第一节 更加简单的语言 2第二节 简单
  11. 特征选择算法之ReliefF算法python实现
  12. java分布式特点_java分布式架构是什么?分布式架构的优缺点有哪些?
  13. 欧姆龙HOSTLINK协议,上位机软件欧姆龙HOSTLINK协议,适合欧姆龙全系列PLC
  14. Packet Tracer使用说明
  15. 【004】VS2017配置OpenCV4.1.0
  16. Vulkan【1】介绍
  17. 关于H5页面背景音乐播放的问题
  18. 《A fast and elitist multiobjective genetic algorithm: NSGA-II》阅读笔记
  19. Http 401错误重现实验及解决办法
  20. 抖音何以为“抖音”?网友:原来如此。。。

热门文章

  1. 520浪漫代码流星雨
  2. 百度推广——搜索营销新视角(百度官方出品,俞敏洪、吴晓波、徐雷力荐!)
  3. Integer对象的大小比较
  4. 浅析竞技游戏匹配机制-ELO算法
  5. 机器学习---数据科学包-第4天
  6. Qt开发北斗定位系统融合百度地图API及Qt程序打包发布
  7. 耳机接口规则_耳机接口种类与标准
  8. 第2章搭建CRM项目开发环境(数据库设计)
  9. Linux启动引导参数grub
  10. 随机森林实现及调参的R与Python对比——以泰坦尼克幸存者数据为例