概述
每次写这个东西 都不知道如何写开头。
…………………………………………………………………………………………………………………….
锲而不舍的学习,就象玉石上的雕刻一样,日子虽长,字迹依旧清晰;
不求甚解的读书,犹如沙石上的记录,后面正在写,前面已被风沙吹盖得无影无踪。
大家都知道ListView 异步加载图片会出现图片错乱现象,这个已经不是问题的问题已经被大家熟悉和解决了,不知道的请戳进来,那么RecyclerView传说是ListView的升级版,那么会不会 出现类似的问题呢。
我们带着问题去一探究竟。
- 第一步:创建Demo 寻找答案。
Activity的布局文件:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/id_recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</RelativeLayout>
大家注意 RecyclerView 是support-v7 包中的。
1、Eclipse 开发者需要 下载 RecyclerView.jar
2、Android Studio 开发者需要 在App目录下的 build.gradle 的dependencies 添加: compile ‘com.android.support:recyclerview-v7:+’
Adapter的布局文件:
<?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">
<ImageView
android:id="@+id/id_imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitXY"
/>
</LinearLayout>
MainActivity代码 :
package cn.com.zyh;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private LinearLayoutManager mLinearLayoutManager;
private MyRecyclerViewAdapter mRecyclerViewAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView) findViewById(R.id.id_recyclerView);
mLinearLayoutManager = new LinearLayoutManager(this);
mLinearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(mLinearLayoutManager);
mRecyclerViewAdapter = new MyRecyclerViewAdapter(this,Images.imageUrls);
mRecyclerView.setAdapter(mRecyclerViewAdapter);
}
}
说明:Activity中 针对RecyclerView 的 声明 赋值 使用;如果是ListView 可以这么使用,但是我们用的是RecyclerView ,所以 有点区别。它需要LinearLayoutManager来管理内部的视图排列方式。当然还需要一个Adapter ,这里我们自己写了一个Adapter。
MyRecyclerViewAdapter:
package cn.com.zyh;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.os.AsyncTask;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import java.io.IOException;
/**
* Created by zyh on 2015/9/15.
*/
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> {
private String [] mImages;
private Context mContext;
private LayoutInflater mInflater;
public MyRecyclerViewAdapter(Context context,String [] imagesUrls){
this.mContext= context;
mImages = imagesUrls;
mInflater = LayoutInflater.from(context);
}
@Override
public MyRecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.recycler_view,parent,false);
ViewHolder holder = new ViewHolder(view);
holder.imageView = (ImageView)view.findViewById(R.id.id_imageView);
return holder;
}
@Override
public void onBindViewHolder(MyRecyclerViewAdapter.ViewHolder holder, int position) {
String imageUrl= mImages[position];
//执行下载操作
DownLoadTask task = new DownLoadTask(holder.imageView);
task.execute(imageUrl);
}
@Override
public int getItemCount() {
return mImages.length;
}
public class ViewHolder extends RecyclerView.ViewHolder {
ImageView imageView;
public ViewHolder(View itemView) {
super(itemView);
}
}
/**
* 异步加载图片
*/
class DownLoadTask extends AsyncTask<String ,Void,BitmapDrawable>{
private ImageView mImageView;
String url;
public DownLoadTask(ImageView imageView){
mImageView = imageView;
}
@Override
protected BitmapDrawable doInBackground(String... params) {
url = params[0];
Bitmap bitmap = downLoadBitmap(url);
BitmapDrawable drawable = new BitmapDrawable(mContext.getResources(),bitmap);
return drawable;
}
private Bitmap downLoadBitmap(String url) {
Bitmap bitmap = null;
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
try {
Response response = client.newCall(request).execute();
bitmap = BitmapFactory.decodeStream(response.body().byteStream());
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
@Override
protected void onPostExecute(BitmapDrawable drawable) {
super.onPostExecute(drawable);
if ( mImageView != null && drawable != null){
mImageView.setImageDrawable(drawable);
}
}
}
}
说明:Adapter中没什么好说的 就是一个简单的异步加载图片。
特殊说明:
1、我使用的是 Okhttp 连接网络 下载图片。
①、Eclipse 开发者需要 自己下载OkHttp 的Jar包
②、Android Studio 开发者需要 在App目录下的 build.gradle 的dependencies 添加: compile ‘com.squareup.okhttp:okhttp:2.0.0’
2、下面一段说明来自 :Hyman 的一篇博客
可以看到数据适配器与BaseAdapter比较发生了相当大的变化,主要有3个方法:
getItemCount 这个不用说,获取总的条目数
onCreateViewHolder 创建ViewHolder
onBindViewHolder 将数据绑定至ViewHolder
可见,RecyclerView对ViewHolder也进行了一定的封装,但是如果你仔细观察,你会发出一个疑问,ListView里面有个getView返回View为Item的布局,那么这个Item的样子在哪控制?
其实是这样的,我们创建的ViewHolder必须继承RecyclerView.ViewHolder,这个RecyclerView.ViewHolder的构造时必须传入一个View,这个View相当于我们ListView getView中的convertView (即:我们需要inflate的item布局需要传入)。
还有一点,ListView中convertView是复用的,在RecyclerView中,是把ViewHolder作为缓存的单位了,然后convertView作为ViewHolder的成员变量保持在ViewHolder中,也就是说,假设没有屏幕显示10个条目,则会创建10个ViewHolder缓存起来,每次复用的是ViewHolder,所以他把getView这个方法变为了onCreateViewHolder。有兴趣的自己打印下Log,测试下。
我们还需要图片s,不得不说的是我很懒。
package cn.com.zyh;
/**
* Created by zyh on 2015/9/15.
*/
public class Images {
public final static String []imageUrls={
"https://img-my.csdn.net/uploads/201508/05/1438760758_3497.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760758_6667.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760757_3588.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760756_3304.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760755_6715.jpeg",
"https://img-my.csdn.net/uploads/201508/05/1438760726_5120.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760726_8364.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760725_4031.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760724_9463.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760724_2371.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760707_4653.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760706_6864.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760706_9279.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760704_2341.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760500_6063.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760499_6304.jpeg",
"https://img-my.csdn.net/uploads/201508/05/1438760499_5081.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760445_3283.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760444_8623.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760444_6822.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760422_2224.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760421_2824.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760420_2660.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760420_7188.jpg",
"https://img-my.csdn.net/uploads/201508/05/1438760419_4123.jpg",
};
}
到这里我们的Demo写完了。
不要忘记在Manifest中添加访问网络的权限
<uses-permission android:name="android.permission.INTERNET"/>
可以测试啦!
测试结果:异步加载图片存在错乱现象。
- 第二步:解决问题。
话说能解决的问题都不是问题。md也不知道谁说的,不过挺有道理的。
解决这个问题的思路和ListView一样,是在Adapter中做修改:
具体代码如下:
package cn.com.zyh;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.support.v7.widget.RecyclerView;
import android.util.LruCache;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import java.io.IOException;
import java.lang.ref.WeakReference;
/**
* Created by zyh on 2015/9/15.
*/
public class MyRecyclerViewAdapter_Best extends RecyclerView.Adapter<MyRecyclerViewAdapter_Best.ViewHolder> {
private String [] mImages;
private Context mContext;
private LayoutInflater mInflater;
private Bitmap mBitmap; //
private LruCache<String ,BitmapDrawable> mMemoryCache;//
public MyRecyclerViewAdapter_Best(Context context,String [] imagesUrls){
this.mContext= context;
mImages = imagesUrls;
mInflater = LayoutInflater.from(context);
//默认显示的图片
mBitmap = BitmapFactory.decodeResource(context.getResources(),R.drawable.default_image);
//计算内存,并且给Lrucache 设置缓存大小
int maxMemory = (int) Runtime.getRuntime().maxMemory();
int cacheSize = maxMemory/6;
mMemoryCache = new LruCache<String ,BitmapDrawable>(cacheSize){
@Override
protected int sizeOf(String key, BitmapDrawable value) {
return value.getBitmap().getByteCount();
}
};
}
@Override
public MyRecyclerViewAdapter_Best.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.recycler_view,parent,false);
ViewHolder holder = new ViewHolder(view);
holder.imageView = (ImageView)view.findViewById(R.id.id_imageView);
return holder;
}
@Override
public void onBindViewHolder(MyRecyclerViewAdapter_Best.ViewHolder holder, int position) {
String imageUrl= mImages[position];
BitmapDrawable drawable = getBitmapDrawableFromMemoryCache(imageUrl);
if (drawable != null){
holder.imageView.setImageDrawable(drawable);
}else if (cancelPotentialTask(imageUrl,holder.imageView)){
//执行下载操作
DownLoadTask task = new DownLoadTask(holder.imageView);
AsyncDrawable asyncDrawable = new AsyncDrawable(mContext.getResources(),mBitmap,task);
holder.imageView.setImageDrawable(asyncDrawable);
task.execute(imageUrl);
}
}
/**
* 检查复用的ImageView中是否存在其他图片的下载任务,如果存在就取消并且返回ture 否则返回 false
* @param imageUrl
* @param imageView
* @return
*/
private boolean cancelPotentialTask(String imageUrl, ImageView imageView) {
DownLoadTask task = getDownLoadTask(imageView);
if (task != null) {
String url = task.url;
if (url == null || !url .equals(imageUrl)){
task.cancel(true);
}else{
return false;
}
}
return true;
}
/**
* 從缓存中获取已存在的图片
* @param imageUrl
* @return
*/
private BitmapDrawable getBitmapDrawableFromMemoryCache(String imageUrl) {
return mMemoryCache.get(imageUrl);
}
/**
* 添加图片到缓存中
* @param imageUrl
* @param drawable
*/
private void addBitmapDrawableToMemoryCache(String imageUrl,BitmapDrawable drawable){
if (getBitmapDrawableFromMemoryCache(imageUrl) == null ){
mMemoryCache.put(imageUrl, drawable);
}
}
/**
* 获取当前ImageView 的图片下载任务
* @param imageView
* @return
*/
private DownLoadTask getDownLoadTask(ImageView imageView){
if (imageView != null){
Drawable drawable = imageView.getDrawable();
if (drawable instanceof AsyncDrawable ){
return ((AsyncDrawable) drawable).getDownLoadTaskFromAsyncDrawable();
}
}
return null;
}
@Override
public int getItemCount() { return mImages.length; }
public class ViewHolder extends RecyclerView.ViewHolder {
ImageView imageView;
public ViewHolder(View itemView) {
super(itemView);
}
}
/**
* 新建一个类 继承BitmapDrawable
* 目的: BitmapDrawable 和DownLoadTask建立弱引用关联
*/
class AsyncDrawable extends BitmapDrawable{
private WeakReference<DownLoadTask> downLoadTaskWeakReference;
public AsyncDrawable(Resources resources,Bitmap bitmap,DownLoadTask downLoadTask){
super(resources,bitmap);
downLoadTaskWeakReference = new WeakReference<DownLoadTask>(downLoadTask);
}
private DownLoadTask getDownLoadTaskFromAsyncDrawable(){
return downLoadTaskWeakReference.get();
}
}
/**
* 异步加载图片
* DownLoadTash 和 ImagaeView建立弱引用关联。
*/
class DownLoadTask extends AsyncTask<String ,Void,BitmapDrawable> {
String url;
private WeakReference<ImageView> imageViewWeakReference;
public DownLoadTask(ImageView imageView){
imageViewWeakReference = new WeakReference<ImageView>(imageView);
}
@Override
protected BitmapDrawable doInBackground(String... params) {
url = params[0];
Bitmap bitmap = downLoadBitmap(url);
BitmapDrawable drawable = new BitmapDrawable(mContext.getResources(),bitmap);
addBitmapDrawableToMemoryCache(url,drawable);
return drawable;
}
/**
* 验证ImageView 中的下载任务是否相同 如果相同就返回
* @return
*/
private ImageView getAttachedImageView() {
ImageView imageView = imageViewWeakReference.get();
if (imageView != null){
DownLoadTask task = getDownLoadTask(imageView);
if (this == task ){
return imageView;
}
}
return null;
}
/**
* 下载图片 这里使用google 推荐使用的OkHttp
* @param url
* @return
*/
private Bitmap downLoadBitmap(String url) {
Bitmap bitmap = null;
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
try {
Response response = client.newCall(request).execute();
bitmap = BitmapFactory.decodeStream(response.body().byteStream());
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
@Override
protected void onPostExecute(BitmapDrawable drawable) {
super.onPostExecute(drawable);
ImageView imageView = getAttachedImageView();
if ( imageView != null && drawable != null){
imageView.setImageDrawable(drawable);
}
}
}
}
写完了,求结果,效果图…..
效果图中的蓝色是我设置的默认背景图。
- 第三步:总结。
这篇文章有两个知识点:
1、基本的RecycleView的使用;
2、解决异步加载图片乱序问题。
本文参考:
1.http://blog.csdn.net/guolin_blog/article/details/45586553
2.http://blog.csdn.net/lmj623565791/article/details/38173061
感谢前辈们的分享。
第一次这儿用心的写文章,还是有些乱。
源码下载
最后
以上就是调皮篮球为你收集整理的使用Android Studio 练习RecyclerView 异步加载图片,解决图片乱序问题。的全部内容,希望文章能够帮你解决使用Android Studio 练习RecyclerView 异步加载图片,解决图片乱序问题。所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复