Android RecyclerView使用 及 滑动时加载图片优化方案
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
//创建默认的线性LayoutManager
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager); // specify an adapter (see also next example)
//设置Adapter
mAdapter = 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的界面进行绑定。
滑动时图片优化方案描述
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时:随用户的操作,屏幕上产生的惯性滑动;
先来瞄瞄activity_main.xml布局文件:
<?xml version=1.0 encoding=utf-?>
<Linearlayout
android:fitssystemwindows="true"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical"
xmlns:android="https://schemas.android.com/apk/res/android"> <Relativelayout
android:background="#00F1A0"
android:id="@+id/layout_titlebar"
android:layout_height="48dp"
android:layout_width="match_parent">
<Textview
android:id="@+id/text_title"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:gravity="center"
android:text="好慌~"
android:textcolor="@android:color/white"
android:textsize="16dp"/>
</Relativelayout> <Framelayout
android:id="@+id/frame_container"
android:layout_height="match_parent"
android:layout_width="match_parent"/>
</Linearlayout>
很简单,用了一个Fragment而已,再来看看主Fragment的布局:
<?xml version=1.0 encoding=utf-?>
<Framelayout
android:background="@android:color/white"
android:layout_height="match_parent"
android:layout_width="match_parent"
xmlns:android="https://schemas.android.com/apk/res/android">
<android.support.v4.widget.SwipeRefreshLayout
android:layout_height="match_parent"
android:layout_width="match_parent">
<org.gaochun.view.AutoLoadRecyclerView
android:id="@+id/recycler_view"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:scrollbars="vertical">
</org.gaochun.view.AutoLoadRecyclerView>
</android.support.v4.widget.SwipeRefreshLayout>
</Framelayout>
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(https://e.hiphotos.baidu.com/image/pic/item/a1ec08fa513d2697e542494057fbb2fb4316d81e.jpg);
mUrls.add(https://c.hiphotos.baidu.com/image/pic/item/30adcbef76094b36de8a2fe5a1cc7cd98d109d99.jpg);
mUrls.add(https://h.hiphotos.baidu.com/image/pic/item/7c1ed21b0ef41bd5f2c2a9e953da81cb39db3d1d.jpg);
mUrls.add(https://g.hiphotos.baidu.com/image/pic/item/55e736d12f2eb938d5277fd5d0628535e5dd6f4a.jpg);
mUrls.add(https://e.hiphotos.baidu.com/image/pic/item/4e4a20a4462309f7e41f5cfe760e0cf3d6cad6ee.jpg);
mUrls.add(https://b.hiphotos.baidu.com/image/pic/item/9d82d158ccbf6c81b94575cfb93eb13533fa40a2.jpg);
mUrls.add(https://e.hiphotos.baidu.com/image/pic/item/4bed2e738bd4b31c1badd5a685d6277f9e2ff81e.jpg);
mUrls.add(https://www.huabian.com/uploadfile/2014/1202/20141202025659854.jpg);
mUrls.add(https://www.huabian.com/uploadfile/2014/1202/20141202025700989.jpg);
mUrls.add(https://g.hiphotos.baidu.com/image/pic/item/0d338744ebf81a4c87a3add4d52a6059252da61e.jpg);
mUrls.add(https://a.hiphotos.baidu.com/image/pic/item/f2deb48f8c5494ee5080c8142ff5e0fe99257e19.jpg);
mUrls.add(https://f.hiphotos.baidu.com/image/pic/item/4034970a304e251f503521f5a586c9177e3e53f9.jpg);
mUrls.add(https://b.hiphotos.baidu.com/image/pic/item/279759ee3d6d55fbb3586c0168224f4a20a4dd7e.jpg);
mUrls.add(https://img2.xkhouse.com/bbs/hfhouse/data/attachment/forum/corebbs/2009-11/2009113011534566298.jpg);
mUrls.add(https://a.hiphotos.baidu.com/image/pic/item/e824b899a9014c087eb617650e7b02087af4f464.jpg);
mUrls.add(https://c.hiphotos.baidu.com/image/pic/item/9c16fdfaaf51f3de1e296fa390eef01f3b29795a.jpg);
mUrls.add(https://d.hiphotos.baidu.com/image/pic/item/b58f8c5494eef01f119945cbe2fe9925bc317d2a.jpg);
mUrls.add(https://h.hiphotos.baidu.com/image/pic/item/902397dda144ad340668b847d4a20cf430ad851e.jpg);
mUrls.add(https://b.hiphotos.baidu.com/image/pic/item/359b033b5bb5c9ea5c0e3c23d139b6003bf3b374.jpg);
mUrls.add(https://a.hiphotos.baidu.com/image/pic/item/8d5494eef01f3a292d2472199d25bc315d607c7c.jpg);
mUrls.add(https://b.hiphotos.baidu.com/image/pic/item/e824b899a9014c08878b2c4c0e7b02087af4f4a3.jpg);
mUrls.add(https://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, );
} 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;
} @Override
public 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;
} @Override
public 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 -
&& dy > ) {
loadMoreListener.loadMore();
isLoadingMore = true;
}
}
} //当屏幕停止滚动时为0;当屏幕滚动且用户使用的触碰或手指还在屏幕上时为1;由于用户的操作,屏幕产生惯性滑动时为2
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) { //根据newState状态做处理
if (imageLoader != null) {
switch (newState) {
case :
imageLoader.resume();
break; case :
if (pauseOnScroll) {
imageLoader.pause();
} else {
imageLoader.resume();
}
break; case :
if (pauseOnFling) {
imageLoader.pause();
} else {
imageLoader.resume();
}
break;
}
}
}
}
也就是说,我们通过定义了一个 setOnPauseListenerParams 方法去设置滑动监听事件setOnScrollListener,并通过定义内部类AutoLoadScrollListener去@Override相关方法并做相应的处理。
Android RecyclerView使用 及 滑动时加载图片优化方案的更多相关文章
- Android ListView只加载当前屏幕内的图片(解决list滑动时加载卡顿)
最近在做ListView分页显示,其中包括图片 和文字(先下载解析文字内容,再异步加载图片)发现每次点击下一页后,文字内容加载完毕,马上向下滑动,由于这时后台在用线程池异步下载图片,我每页有20条,也 ...
- 【Android】首次进入应用时加载引导界面
参考文章: [1]http://blog.csdn.net/wsscy2004/article/details/7611529 [2]http://www.androidlearner.net/and ...
- json解析,异步下载(listview仅滑动时加载)Demo总结
异步加载的练习demo 主要涉及知识点: 1.解析json格式数据,主要包括图片,文本 2.使用AsynTask异步方式从网络下载图片 3.BaseAdapter的"优雅"使用 4 ...
- android Listview 软引用SoftReference异步加载图片
首先说一下,android系统加载大量图片系统内存溢出的3中解决方法: (1)从网络或本地加载图片的时候,只加载缩略图.这个方法的确能够少占用不少内存,可是它的致命的缺点就是,因为加载的是缩略图,所以 ...
- web性能优化之---JavaScript中的无阻塞加载性能优化方案
一.js阻塞特性 JS 有个很无语的阻塞特性,就是当浏览器在执行JS 代码时,不能同时做其他任何事情,无论其代码是内嵌的还是外部的. 即<script>每次出现都会让页面等待脚本的解析和执 ...
- vue-cli3.0 资源加载的优化方案
20180829 更新 今天反复试了,不用区分 测试环境还是 生产环境,统一都用 cdn 就可以了 背景 之前自己搭建了一个 vue + tp5.1 的后台项目(https://segmentfaul ...
- Android Studio [ImageView/使用第三方库加载图片]
ImageViewActivity.class package com.xdw.a122; import android.support.v7.app.AppCompatActivity; impor ...
- UGUI加载图片优化方法之一:打包成图集
打包后的: 直接改变sprite中的packing tag,相同的packing tag就是同一张图集中的.改完运行会自动帮你打包
- Android 高清加载巨图方案 拒绝压缩图片
Android 高清加载巨图方案 拒绝压缩图片 转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/49300989: 本文出自:[张 ...
随机推荐
- 一些非常有用的工具类之javamail(from韩顺平)
之前编写一个类淘宝服务器时,需要使用javamail发送邮件,搜到的一个工具类,很有用. 需要下载导入:activation.jar和mail.jar package com.cx.service; ...
- 交友app
编辑注记:这是由译者 han_qi 翻译纽约客的一篇文章,从女性的角度描写了交友产品的用户体验及需求,值得广大产品经理深入研究,文章略长,但值得深读.原文<Overwhelmed and Cre ...
- 从理论到实践,全方位认识DNS(实践篇)
在理论篇中,我们基本了解了DNS的整个协议原理,但是可能还会有着下面的疑问: 为什么我想申请的域名都没了? DNS 域名还要备案,这是为什么啊? 如何将刚申请的域名绑定到自己的网站呢? 怎么才能看到那 ...
- 我的Android进阶之旅------>Android的ListView数据更新后,怎样使最新的条目能够自己主动滚动到可视范围内?
在ListView的layout配置中加入 android:transcriptMode="alwaysScroll" <ListView android:id=" ...
- CoreData使用方法三: NSPredicate在CoreData中的使用
NSPredicate在CoreData中经常使用作查询使用,相当于sql语句中的where查询子句. 最经常使用的方法为: NSPredicate *ca = [NSPredicate predic ...
- 【Cocos2dx游戏开发】Cocos2d-x简介
一.简介 最近在做一个Android下的卡牌游戏--<九州幻想>开发项目,而我们使用的引擎是Cocos2dx,所以想要写写笔记来记录一下项目中的收获.当然首先稍微介绍一下Cocos2d-x ...
- Codeforces 91C Ski Base 加边求欧拉回路数量
题目链接:点击打开链接 题意: 给出n个点m条无向边的图 開始图里没有边.每次加一条边,然后输出图里欧拉回路的条数. 思路: We will count the number of ski bases ...
- struts2 一个CRUD的BaseAction
在struts2 in action中所见,这样封装后省去了大部分crud反复代码.尽管还不能理悟.先记下来. abstract class BaseAction extends ActionSupp ...
- swift手记-6
// // ViewController.swift // learn // // Created by myhaspl on 16/1/26. // Copyright (c) 2016年 myha ...
- 技术的止境(客户价值第一,快速实现第二,边做边学,迅速成为牛人。紧贴客户的需求去做技术,立于不败之地。追求的目标:把一项产品去做好,用产品去养活自己和家人)good
作为一个依靠技术来谋生的程序员,我最近一直在思考一个问题,有限的生命里,面对无限的技术更新,我要研究到什么程度才能算是完成我的成为技术大牛的目标呢?换而言之,那就是技术的止境在哪儿呢?深入的思考下去, ...