您的位置:首页 > 移动开发

【OSC手机App技术解析】- 列表异步线程加载图片

2012-07-23 15:12 411 查看
手机客户端以列表形式展示数据是非常常见的一种方式。然而列表中要显示图片(比如:头像)就要采用异步线程加载的方式,这样做是为了防止加载图片数据的时候,花费时间过长,阻塞UI线程,从而达到保持App的流畅性的目的。

下面我将分享 OSChina.NET Android版客户端的列表异步线程加载图片的方法:





图片缓存

private static HashMap<String, SoftReference<Bitmap>> cache;


图片缓存是当有加载过相同的图片的时候,可以快速重复使用,比如同一个人的头像。

图片控件集合

private static Map<ImageView, String> imageViews;

图片控件集合是一个Map,记录当前ImageView控件对应的图片地址,用来防止异步线程加载图片时候ImageView控件显示的图片与实际图片地址对应的图片不符,出现错乱。

线程池

private static ExecutorService pool;


固定线程池里的并发线程数,可以防止用户在快速滑动列表的时候,不执行已经滑过去的加载线程。
具体的初始化代码:

static {
cache = new HashMap<String, SoftReference<Bitmap>>();
pool = Executors.newFixedThreadPool(5);  //固定线程池
imageViews = Collections.synchronizedMap(new WeakHashMap<ImageView, String>());
}


接下来,我们来看看具体是如何加载图片的:

public void loadBitmap(String url, ImageView imageView, Bitmap defaultBmp, int width, int height) {
imageViews.put(imageView, url);
Bitmap bitmap = getBitmapFromCache(url);

if (bitmap != null) {
//显示缓存图片
imageView.setImageBitmap(bitmap);
} else {
//加载SD卡中的图片缓存
String filename = FileUtils.getFileName(url);
String filepath = imageView.getContext().getFilesDir() + File.separator + filename;
File file = new File(filepath);
if(file.exists()){
//显示SD卡中的图片缓存
Bitmap bmp = ImageUtils.getBitmap(imageView.getContext(), filename);
imageView.setImageBitmap(bmp);
}else{
//线程加载网络图片
imageView.setImageBitmap(defaultBmp);
queueJob(url, imageView, width, height);
}
}
}


上面的代码中,我们根据图片的url地址,先从图片缓存里面查找是否已缓存过,如果没有,再从SD卡的图片缓存文件中查找,如果再没有,最后才是加载网络图片。这才是以最快速的方式显示图片。

下面,我将贴出完整的代码:

/**
* 异步线程加载图片工具类
* @author liux
*/
public class BitmapManager {

private static HashMap<String, SoftReference<Bitmap>> cache;
private static ExecutorService pool;
private static Map<ImageView, String> imageViews;
private Bitmap defaultBmp;

static { cache = new HashMap<String, SoftReference<Bitmap>>(); pool = Executors.newFixedThreadPool(5); //固定线程池 imageViews = Collections.synchronizedMap(new WeakHashMap<ImageView, String>()); }

public BitmapManager(){}

public BitmapManager(Bitmap def) {
this.defaultBmp = def;
}

/**
* 设置默认图片
* @param bmp
*/
public void setDefaultBmp(Bitmap bmp) {
defaultBmp = bmp;
}

/**
* 加载图片
* @param url
* @param imageView
*/
public void loadBitmap(String url, ImageView imageView) {
loadBitmap(url, imageView, this.defaultBmp, 0, 0);
}

/**
* 加载图片-可设置加载失败后显示的默认图片
* @param url
* @param imageView
* @param defaultBmp
*/
public void loadBitmap(String url, ImageView imageView, Bitmap defaultBmp) {
loadBitmap(url, imageView, defaultBmp, 0, 0);
}

/**
* 加载图片-可指定显示图片的高宽
* @param url
* @param imageView
* @param width
* @param height
*/
public void loadBitmap(String url, ImageView imageView, Bitmap defaultBmp, int width, int height) {
imageViews.put(imageView, url);
Bitmap bitmap = getBitmapFromCache(url);

if (bitmap != null) {
//显示缓存图片
imageView.setImageBitmap(bitmap);
} else {
//加载SD卡中的图片缓存
String filename = FileUtils.getFileName(url);
String filepath = imageView.getContext().getFilesDir() + File.separator + filename;
File file = new File(filepath);
if(file.exists()){
//显示SD卡中的图片缓存
Bitmap bmp = ImageUtils.getBitmap(imageView.getContext(), filename);
imageView.setImageBitmap(bmp);
}else{
//线程加载网络图片
imageView.setImageBitmap(defaultBmp);
queueJob(url, imageView, width, height);
}
}
}

/**
* 从缓存中获取图片
* @param url
*/
public Bitmap getBitmapFromCache(String url) {
Bitmap bitmap = null;
if (cache.containsKey(url)) {
bitmap = cache.get(url).get();
}
return bitmap;
}

/**
* 从网络中加载图片
* @param url
* @param imageView
* @param width
* @param height
*/
public void queueJob(final String url, final ImageView imageView, final int width, final int height) {
final Handler handler = new Handler() {
public void handleMessage(Message msg) {
String tag = imageViews.get(imageView);
if (tag != null && tag.equals(url)) {
if (msg.obj != null) {
imageView.setImageBitmap((Bitmap) msg.obj);
try {
//向SD卡中写入图片缓存
ImageUtils.saveImage(imageView.getContext(), FileUtils.getFileName(url), (Bitmap) msg.obj);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
};

pool.execute(new Runnable() {
public void run() {
Message message = Message.obtain();
message.obj = downloadBitmap(url, width, height);
handler.sendMessage(message);
}
});
}

/**
* 下载图片-可指定显示图片的高宽
* @param url
* @param width
* @param height
*/
private Bitmap downloadBitmap(String url, int width, int height) {
Bitmap bitmap = null;
try {
//http加载图片
bitmap = ApiClient.getNetBitmap(url);
if(width > 0 && height > 0) {
//指定显示图片的高宽
bitmap = Bitmap.createScaledBitmap(bitmap, width, height, true);
}
//放入缓存
cache.put(url, new SoftReference<Bitmap>(bitmap));
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
}


工具类使用

实例化时,可以设置默认的显示图片:

BitmapManager bmpManager = new BitmapManager(BitmapFactory.decodeResource(context.getResources(), R.drawable.loading));


调用加载图片的方法:

bmpManager.loadBitmap(imageURL, imageView);


如果大家有什么疑问的话,欢迎在下面回帖一起探讨。

PS:

OSC Android客户端下载地址: http://www.oschina.net/uploads/osc.apk

OSC iPhone客户端下载地址: http://www.oschina.net/uploads/osc.ipa

OSC Windows Phone客户端下载地址: http://www.oschina.net/uploads/osc.xap

转载:http://www.oschina.net/question/157182_59454
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: