首先声明,参考博客地址:http://www.iteye.com/topic/685986

对于ListView,相信很多人都很熟悉,因为确实太常见了,所以,做的用户体验更好,就成了我们的追求。。。

常见的ListView中很少全是文字的,一般都是图文共存的,而图片的来源是服务器端(很少有写在客户端的吧。。。考虑客户端的大小和更新的问题),所以,网络问题就成了图片是否能顺利加载成功的决定性因素了。大家都知道每次启动一个Android应用,都会启动一个UI主线程,主要是响应用户的交互,如果我们把不确定的获取网络图片的操作放在UI主线程,结果也就不确定了。。。当然,如果你网络足够好的话,应该问题不大,但是,网络谁能保证呢?所以就出现了“异步加载”的方法!

我先叙述一下异步加载的原理,说的通俗一点就是UI主线程继续做与用户交互的响应监听和操作,而加载图片的任务交到其他线程中去做,当图片加载完成之后,再跟据某种机制(比如回调)绘制到要显示的控件中。

首先,贴出AsyncBitmapLoader.java,这个类是关键,主要做的就是当加载图片的时候,去缓冲区查找,如果有的话,则立刻返回Bitmap对象,省掉再去网络服务器下载的时间和流量。

<span style="font-size:18px;">package onerain.ald.async;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.util.HashMap; import onerain.ald.common.HttpUtils;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;
import android.widget.ImageView; /**
* @author oneRain
**/
public class AsyncBitmapLoader
{
/**
* 内存图片软引用缓冲
*/
private HashMap<String, SoftReference<Bitmap>> imageCache = null; public AsyncBitmapLoader()
{
imageCache = new HashMap<String, SoftReference<Bitmap>>();
} public Bitmap loadBitmap(final ImageView imageView, final String imageURL, final ImageCallBack imageCallBack)
{
//在内存缓存中,则返回Bitmap对象
if(imageCache.containsKey(imageURL))
{
SoftReference<Bitmap> reference = imageCache.get(imageURL);
Bitmap bitmap = reference.get();
if(bitmap != null)
{
return bitmap;
}
}
else
{
/**
* 加上一个对本地缓存的查找
*/
String bitmapName = imageURL.substring(imageURL.lastIndexOf("/") + );
File cacheDir = new File("/mnt/sdcard/test/");
File[] cacheFiles = cacheDir.listFiles();
int i = ;
for(; i<cacheFiles.length; i++)
{
if(bitmapName.equals(cacheFiles[i].getName()))
{
break;
}
} if(i < cacheFiles.length)
{
return BitmapFactory.decodeFile("/mnt/sdcard/test/" + bitmapName);
}
} final Handler handler = new Handler()
{
/* (non-Javadoc)
* @see android.os.Handler#handleMessage(android.os.Message)
*/
@Override
public void handleMessage(Message msg)
{
// TODO Auto-generated method stub
imageCallBack.imageLoad(imageView, (Bitmap)msg.obj);
}
}; //如果不在内存缓存中,也不在本地(被jvm回收掉),则开启线程下载图片
new Thread()
{
/* (non-Javadoc)
* @see java.lang.Thread#run()
*/
@Override
public void run()
{
// TODO Auto-generated method stub
InputStream bitmapIs = HttpUtils.getStreamFromURL(imageURL); Bitmap bitmap = BitmapFactory.decodeStream(bitmapIs);
imageCache.put(imageURL, new SoftReference<Bitmap>(bitmap));
Message msg = handler.obtainMessage(, bitmap);
handler.sendMessage(msg); File dir = new File("/mnt/sdcard/test/");
if(!dir.exists())
{
dir.mkdirs();
} File bitmapFile = new File("/mnt/sdcard/test/" +
imageURL.substring(imageURL.lastIndexOf("/") + ));
if(!bitmapFile.exists())
{
try
{
bitmapFile.createNewFile();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
FileOutputStream fos;
try
{
fos = new FileOutputStream(bitmapFile);
bitmap.compress(Bitmap.CompressFormat.JPEG,
, fos);
fos.close();
}
catch (FileNotFoundException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start(); return null;
} /**
* 回调接口
* @author onerain
*
*/
public interface ImageCallBack
{
public void imageLoad(ImageView imageView, Bitmap bitmap);
}
}
</span>

PS:我这里用到了两个缓冲,一是内存缓存,一个是本地缓存(即SD卡缓存),其中用到了SoftReference,这个类的主要作用是生成一个“软引用”,你可以认为是一种随时会由于JVM垃圾回收机制回收掉的Map对象(而平时我们所用到的引用不释放的话不会被JVM回收),之所以用到软引用,就是考虑到android对图片的缓存是有大小限制的,当超过这个大小时,就一定要释放,如果你用引用,保持不释放的话,那么FC(Force close)就离你不远了。。。我这里还用到了一个本地缓存的机制,是和参考博客不太一样的地方,只是提供一种思路,方法还没有完善(主要因为和服务器还没约定好关于图片的命名规则),主要作用是在用户浏览过大量图片之后(超过内存缓存容量之后),保留在本地,一是为了提高读取速度,二是可以减少流量消耗!

这个类设计好之后,在自定义的Adapter当中比之前会有些不同,先上代码再解释

<span style="font-size:18px;">package onerain.ald.adapter;

import java.util.List;

import onerain.ald.R;
import onerain.ald.async.AsyncBitmapLoader;
import onerain.ald.async.AsyncBitmapLoader.ImageCallBack;
import onerain.ald.entity.BaseBookEntity;
import onerain.ald.holder.ViewHolder;
import android.content.Context;
import android.graphics.Bitmap;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView; /**
* @author oneRain
**/
public class ListAdapter extends BaseAdapter
{
private Context context = null;
private List<BaseBookEntity> bookList = null; private AsyncBitmapLoader asyncLoader = null; public ListAdapter(Context context, List<BaseBookEntity> bookList)
{
this.context = context;
this.bookList = bookList;
this.asyncLoader = new AsyncBitmapLoader();
} @Override
public int getCount()
{
// TODO Auto-generated method stub
return bookList.size();
} @Override
public Object getItem(int position)
{
// TODO Auto-generated method stub
return bookList.get(position);
} @Override
public long getItemId(int position)
{
// TODO Auto-generated method stub
return position;
} @Override
public View getView(int position, View convertView, ViewGroup parent)
{
// TODO Auto-generated method stub
ViewHolder holder = null; if(convertView == null)
{
LayoutInflater inflater = LayoutInflater.from(context);
convertView = inflater.inflate(R.layout.item, null); holder = new ViewHolder((ImageView)convertView.findViewById(R.id.imageView),
(TextView)convertView.findViewById(R.id.textView));
convertView.setTag(holder);
}
else
{
holder = (ViewHolder) convertView.getTag();
} ImageView imageView = holder.getImageView(); <span style="color:#FF0000;">imageView.setImageBitmap(null);</span> &nbsp; //根据图片URL去查找内存缓存有没有对应的Bitmap对象,并传递回调方法,如果没有,则等下载完毕回调
Bitmap bitmap = asyncLoader.loadBitmap(imageView,
bookList.get(position).getBook_pic(),
new ImageCallBack()
{
@Override
public void imageLoad(ImageView imageView, Bitmap bitmap)
{
// TODO Auto-generated method stub
imageView.setImageBitmap(bitmap);
}
}); if(bitmap == null)
{
imageView.setImageResource(R.drawable.ic_launcher);
}
else
{
imageView.setImageBitmap(bitmap);
} holder.getTextView().setText(bookList.get(position).getTitle()); return convertView;
}
}
</span>

在Adapter中,主要不同表现在

public View getView(int position, View convertView, ViewGroup parent)方法中(我这里用到了一些优化方面的处理,会在其他时间再与大家分享,今天先不解释),和异步加载最相关的是这一段

<span style="font-size:18px;">ImageView imageView = holder.getImageView();
//根据图片URL去查找内存缓存有没有对应的Bitmap对象,并传递回调方法,如果没有,则等下载完毕回调
Bitmap bitmap = asyncLoader.loadBitmap(imageView,
bookList.get(position).getBook_pic(),
new ImageCallBack()
{
@Override
public void imageLoad(ImageView imageView, Bitmap bitmap)
{
// TODO Auto-generated method stub
imageView.setImageBitmap(bitmap);
}
}); if(bitmap == null)
{
imageView.setImageResource(R.drawable.ic_launcher);
}
else
{
imageView.setImageBitmap(bitmap);
}</span>

asyncLoader是我们定义的异步加载类的对象,通过这个类的

public Bitmap loadBitmap(final ImageView imageView, final String imageURL, final ImageCallBack imageCallBack)

加载图片,传递参数也与参考博客有些不同,我觉得这样更好理解一下,就是要显示图片的URL链接,和图片要显示对应的控件,当然最重要的还有这个接口实现的回调对象,是在线程中下载完图片之后,用以加载图片的回调对象。而这个回调对象在传递的时候已经实现了接口方法,即将下载好的图片绘制在对应的控件之中

<span style="font-size:18px;">imageView.setImageBitmap(bitmap);</span>

最新文章

  1. 前端学PHP之面向对象系列第一篇——类和对象
  2. 【代码笔记】iOS-图片旋转
  3. Coursera台大机器学习课程笔记7 -- Noise and Error
  4. Android SDK Manager 无法下载更新,或者更新速度超慢,或者待安装包列表不显示
  5. 夺命雷公狗-----React---4--props变量的传递
  6. Docker基础技术:Linux Namespace(下)
  7. 对easyUI中课堂源码编辑改进建议
  8. Linux CPU 亲和性
  9. 同步fifo的verilogHDL设计实例
  10. 源码阅读之mongoengine(0)
  11. MMORPG战斗系统随笔(三)、AI系统简介
  12. win10 uwp MVVM入门
  13. Docker中完成Jenkins的安装
  14. OA发展史:由点到生态
  15. 使用synchronized同步,经典银行账户问题
  16. 刷完500道BAT面试题,我能去面试大厂了吗?
  17. 题解 SP26045 【GCDMAT2 - GCD OF MATRIX (hard)】
  18. map/reduce/filter/lambda
  19. js有关事件驱动
  20. 搭建windows远程节点_jmeter自动化测试环境(接口测试)

热门文章

  1. ImageView的属性android:scaleType
  2. c中计时的几种方法
  3. Javaweb入门20160301 ---xml入门
  4. zoj2432 hdoj1423 最长公共上升子序列(LCIS)
  5. ASP.NET页面生命周期总结(1)
  6. 贪心算法:旅行商问题(TSP)
  7. (转)UIColor,CGColor,CIColor三者的区别和联系
  8. getDrawingRect,getHitRect,getLocalVisibleRect,getGlobalVisibleRect
  9. PHP接口(interface)和抽象类(abstract)
  10. poj 1681 Painter&#39;s Problem