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

这几天为了解决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环境来开发的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值