您的位置:首页 > 其它

解决ListView中在滚动时已经下载缓存的图片没有显示

2015-07-22 14:34 363 查看
这几天为了解决ListView在滚动时已经下载缓存的图片时而显示,时而不显示的问题,在网上找了不少资料,伤了不少的脑细胞,而昨天虽然找到了解决方法但发现这种方法非常占资源,执行起来不顺畅,有卡的现象,今天又在网上找了一些资料,终于找到最好的解决方法,现在将解决方案做下记录

1、异步加载图片代码:

import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Handler;
import android.util.Log;
public class AsyncImageLoader {
//保存正在下载的图片URL集合,避免重复下载用
private static HashSet<String> sDownloadingSet;
//软引用内存缓存
private static Map<String, SoftReference<Bitmap>> sImageCache;
//图片三种获取方式管理者,网络URL获取、内存缓存获取、外部文件缓存获取
private static LoaderImpl impl;
//线程池相关
private static ExecutorService sExecutorService;
//通知UI线程图片获取ok时使用
private Handler handler;
/**
* 异步加载图片完毕的回调接口
*/
public interface ImageCallback {
/**
* 回调函数
*
* @param bitmap:  may be null!
* @param imageUrl
*/
public void onImageLoaded(Bitmap bitmap, String imageUrl);
}
static {
sDownloadingSet = new HashSet<String>();
sImageCache = new HashMap<String, SoftReference<Bitmap>>();
impl = new LoaderImpl(sImageCache);
}
public AsyncImageLoader(Context context) {
handler = new Handler();
startThreadPoolIfNecessary();
String defaultDir = context.getCacheDir().getAbsolutePath();
setCachedDir(defaultDir);
}
/**
* 是否缓存图片至/data/data/package/cache/目录
* 默认不缓存
*/
public void setCache2File(boolean flag) {
impl.setCache2File(flag);
}
/**
* 设置缓存路径,setCache2File(true)时有效
*/
public void setCachedDir(String dir) {
impl.setCachedDir(dir);
}
/**
* 开启线程池
*/
public static void startThreadPoolIfNecessary() {
if (sExecutorService == null || sExecutorService.isShutdown() || sExecutorService.isTerminated()) {
sExecutorService = Executors.newFixedThreadPool(3);
//sExecutorService = Executors.newSingleThreadExecutor();
}
}
/**
* 异步下载图片,并缓存到memory中
*
* @param url
* @param callback see ImageCallback interface
*/
public void downloadImage(final String url, final ImageCallback callback) {
downloadImage(url, true, callback);
}
/**
* @param url
* @param cache2Memory 是否缓存至memory中
* @param callback
*/
public void downloadImage(final String url, final boolean cache2Memory, final ImageCallback callback) {
if (sDownloadingSet.contains(url)) {
Log.i("AsyncImageLoader", "###该图片正在下载,不能重复下载!");
return;
}
Bitmap bitmap = impl.getBitmapFromMemory(url);
if (bitmap != null) {
if (callback != null) {
callback.onImageLoaded(bitmap, url);
}
} else {
//从网络端下载图片
sDownloadingSet.add(url);
sExecutorService.submit(new Runnable() {
@Override
public void run() {
final Bitmap bitmap = impl.getBitmapFromUrl(url, cache2Memory);
handler.post(new Runnable() {
@Override
public void run() {
if (callback != null)
callback.onImageLoaded(bitmap, url);
sDownloadingSet.remove(url);
}
});
}
});
}
}
/**
* 预加载下一张图片,缓存至memory中
*
* @param url
*/
public void preLoadNextImage(final String url) {
//将callback置为空,只将bitmap缓存到memory即可。
downloadImage(url, null);
}
}


2、判断是否已经存在下载缓存图片方法:

//加载图片
public static Bitmap getURLImage(Context context, String key, LruCache<String, Bitmap> lruCache) {
Bitmap bitmap = lruCache.get(key);
// 判断是否已经存在缓存图片
if (bitmap == null) {
//如果不存在就自动异步加载
bitmap = initAsyncImageLoader(context, key);
}
return bitmap;
}
private static Bitmap initAsyncImageLoader(Context context, String url) {
final Bitmap[] bmp = {null};
AsyncImageLoader loader = new AsyncImageLoader(context.getApplicationContext());
//将图片缓存至外部文件中
loader.setCache2File(true);
//设置外部缓存文件夹
createCacheDir(context, "image");
loader.setCachedDir(dirPath);
//下载图片,第二个参数是否缓存至内存中
loader.downloadImage(url, true, new AsyncImageLoader.ImageCallback() {
@Override
public void onImageLoaded(Bitmap bitmap, String imageUrl) {
bmp[0] = bitmap;
}
});
return bmp[0];
}


3、adapter 中的代码:

//获取当前应用程序所分配的最大内存
int maxMemory = (int) Runtime.getRuntime().maxMemory();
//只分5分之一用来做图片缓存
int cacheSize = maxMemory / 5;
LruCache<String, Bitmap> mLruCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
//复写sizeof()方法
//这里是按多少KB来算
return value.getRowBytes() * value.getHeight() / 1024;
}
};
@Override
public View getView(int position, View convertView, ViewGroup parent) {
JSONObject item_data = getItem(position);
if (convertView != null) {  //节约视图资源
ll = (LinearLayout) convertView.getTag();
ImageView imageView_image = (ImageView) ll.findViewById(R.id.imageview_image);
imageView_image.setImageResource(R.drawable.iconfont_loading);
} else {
ll = (LinearLayout) LayoutInflater.from(mcontext).inflate(R.layout.adapter_listview_product, null);
ll.setTag(ll);
}

ImageView imageView_image = (ImageView) ll.findViewById(R.id.imageview_image);

try {
String offerId = String.valueOf(item_data.getString("offerId"));

//图片资源
String image_url = item_data.getString("image");
imageView_image.setTag(offerId);
//得到可用的图片
if (offerId == imageView_image.getTag()) {
Bitmap bitmap = FileUtil.getURLImage(mcontext, image_url, mLruCache);
if (bitmap != null) {
if (mLruCache.get(image_url) == null) {
mLruCache.put(image_url,bitmap);
}
imageView_image.setImageBitmap(bitmap);
} else {
imageView_image.setImageResource(R.drawable.iconfont_loading);
}
}
textView_saledCount.setText(String.valueOf(item_data.getInt("saledCount")));
} catch (JSONException e) {
e.printStackTrace();
}
return ll;


以上我在Android 4.0.3 以上测试是完全没有问题,因为我现在开发都是基于4.0环境来开发的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: