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

Android ListView图片异步加载显示

2014-10-05 14:40 567 查看
模拟android中的消息机制实现图片的异步加载和动态显示

packagecn.jd3g.utils;

importjava.lang.ref.SoftReference;
importjava.util.HashMap;
importjava.util.LinkedHashMap;
importjava.util.Map.Entry;

importandroid.graphics.Bitmap;
importandroid.os.Handler;
importandroid.util.Log;
importandroid.widget.ImageView;

/**
* 利用多线程异步加载图片并更新视图
*
* @author xfzhang
*
*/
publicfinal class AsynImageLoader {

privateLoaderThread thread;// 加载图片并发消息通知更新界面的线程
privateHashMap<String, SoftReference<Bitmap>> imageCache;// 图片对象缓存,key:图片的url
privateHandler handler;// 界面Activity的Handler对象

publicAsynImageLoader(Handler handler) {
imageCache = newHashMap<String, SoftReference<Bitmap>>();
this.handler = handler;
}

/**
* 加载图片前显示到指定的ImageView中,图片的url保存在视图对象的Tag中
*
* @param imageView
*            要显示图片的视图
* @param defaultBitmap
*            加载需要显示的提示正在加载的默认图片对象
*/
publicvoid loadBitmap(ImageView imageView, Bitmap defaultBitmap) {
// 图片所对应的url,这个值在加载图片过程中很可能会被改变
String url = (String) imageView.getTag();
if(imageCache.containsKey(url)) {// 判断缓存中是否有
SoftReference<Bitmap> softReference = imageCache.get(url);
Bitmap bitmap = softReference.get();
if(bitmap != null) {// 如果图片对象不为空,则可挂接更新视图,并返回
imageView.setImageBitmap(bitmap);
return;
} else{// 如果为空,需要将其从缓存中删除(其bitmap对象已被回收释放,需要重新加载)
Log.e("TAG", "cache bitmap is null");
imageCache.remove(url);
}
}
imageView.setImageBitmap(defaultBitmap);// 先显示一个提示正在加载的图片
if(thread == null) {// 加载线程不存在,线程还未启动,需要新建线程并启动
thread = newLoaderThread(imageView, url);
thread.start();
} else{// 如果存在,就调用线程对象去加载
thread.load(imageView, url);
}

}

/**
* 释放缓存中所有的Bitmap对象,并将缓存清空
*/
publicvoid releaseBitmapCache() {
if(imageCache != null) {
for(Entry<String, SoftReference<Bitmap>> entry : imageCache.entrySet()) {
Bitmap bitmap = entry.getValue().get();
if(bitmap != null) {
bitmap.recycle();// 释放bitmap对象
}
}
imageCache.clear();
}
}

/**
* 加载图片并显示的线程
*/
privateclass LoaderThread extendsThread {

LinkedHashMap<String, ImageView> mTaskMap;// 需要加载图片并显示的图片视图对象任务链
privateboolean mIsWait;// 标识是线程是否处于等待状态

publicLoaderThread(ImageView imageView, String url) {
mTaskMap = newLinkedHashMap<String, ImageView>();
mTaskMap.put(url, imageView);
}

/**
* 处理某个视图的更新显示
*
* @param imageView
*/
publicvoid load(ImageView imageView, String url) {
mTaskMap.remove(imageView);// 任务链中可能有,得先删除
mTaskMap.put(url, imageView);// 将其添加到任务中
if(mIsWait) {// 如果线程此时处于等待得唤醒线程去处理任务队列中待处理的任务
synchronized(this) {// 调用对象的notify()时必须同步
this.notify();
}
}
}

@Override
publicvoid run() {
while(mTaskMap.size() > 0) {// 当队列中有数据时线程就要一直运行,一旦进入就要保证其不会跳出循环
mIsWait = false;
finalString url  = mTaskMap.keySet().iterator().next();
finalImageView imageView = mTaskMap.remove(url);
if(imageView.getTag() == url) {// 判断视图有没有复用(一旦ImageView被复用,其tag值就会修改变)
finalBitmap bitmap = MyConnection.getBitmapByUrl(url);// 此方法应该是从网络或sd卡中加载
try{
Thread.sleep(1000);// 模拟网络加载数据时间
} catch(InterruptedException e1) {
e1.printStackTrace();
}
// 将加载的图片放入缓存map中
imageCache.put(url, newSoftReference<Bitmap>(bitmap));
if(url == imageView.getTag()) {// 再次判断视图有没有复用
handler.post(newRunnable() {// 通过消息机制在主线程中更新UI
@Override
publicvoid run() {
imageView.setImageBitmap(bitmap);
}
});
}
}
if(mTaskMap.isEmpty()) {// 当任务队列中没有待处理的任务时,线程进入等待状态
try{
mIsWait = true;// 标识线程的状态,必须在wait()方法之前
synchronized(this) {
this.wait();// 保用线程进入等待状态,直到有新的任务被加入时通知唤醒
}
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}


<span style="font-size:14px;">privateclass ProductListAdapter extendsBaseAdapter {

privateAsynImageLoader mImageAsynLoader;

publicProductListAdapter() {
mImageAsynLoader = newAsynImageLoader(mHandler);
}

@Override
publicint getCount() {
intsize = Math.min(mLastItemViewIndex + 1, mDataList.size());
mLastItemViewIndex = size - 1;
returnsize;
}

@Override
publicObject getItem(intposition) {
returnmDataList.get(position);
}

@Override
publiclong getItemId(intposition) {
returnposition;
}

@Override
publicView getView(intposition, View convertView, ViewGroup parent) {
if(convertView == null) {
convertView = getLayoutInflater().inflate(R.layout.product_list_item,
null);
}
ImageView imageView = (ImageView) convertView
.findViewById(R.id.iv_item_product_image);
Map<String, String> map = mDataList.get(position);
//存放图片所对应的url
imageView.setTag(map.get("product_pic_address"));
mImageAsynLoader.loadBitmap(imageView, mDefautBitmap);
returnconvertView;
}
}</span>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: