如何通过自定义线程池去实现一个简单的图片ImageLoader

话说接触自定义线程池的时候还是几年前用Volley框架的时候,当时就注意到了一个东西叫队列,后来在实际开发中也没有用到相关的东西,只是写过简单的demo而已,现在各种框架很成熟,用多了就缺少了动手能力,所以我就简单了实现了这个框架。

整成思路是:默认创建了5个线程,通过LinkedBlockingQueue去管理线程执行请求,当没有任务时等待执行任务,当有任务来的时候就去执行线程,当任务超过时就排队等待。当在列表中去执行任务时,例如在listview中下载图片,为了防止图片错乱,我们用一个ConcurrentHashMap去维护,如果请求时的url和请求后的url是同一个url那么就是对的。并用LruCache去缓存图片。

以下是代码部分。
先看下downLoadImages这个方法,如果缓存中有对应得图片就直接设置,否则去下载。
为什么下载图片时要先 imageView.setImageBitmap(null);执行这句代码呢,由于listview的缓存机制,它会重用缓存的view导致view的图片还是之前缓存的,滑动时图片会覆盖产生一闪一闪的效果,体验很不好。

public class ImageLoderUtils implements HandlerCallbackImp{

    private static final ImageLoderUtils mImageLoderUtils = new ImageLoderUtils();

    private LruCache<String,Bitmap> mImageCache;
    private ThreadManager mThreadManager;
    private static final String TAG = "tag";
    privateImageLoderUtils(){
        mThreadManager = new ThreadManager(this);
        mImageCache = mThreadManager.getImageCache();
    }

    public static ImageLoderUtils getInstance(){
        return mImageLoderUtils;
    }


    public Bitmap getBitmapFromCache(String url){
        if(url.isEmpty()){
            return null;
        }
        Bitmap bitmap = mImageCache.get(url);
        return bitmap;
    }

    public void downLoadImages(String imageUrl,final ImageView imageView){
        imageView.setImageBitmap(null);
        Bitmap cacheBitmap = getBitmapFromCache(imageUrl);
        if(cacheBitmap != null){
            imageView.setImageBitmap(cacheBitmap);
        }else{
            BlockQueueParams blockQueueParams = new BlockQueueParams(imageView,imageUrl);
            mThreadManager.putRequestQueue(blockQueueParams);
        }

    }

    @Override
    public void handlerMsg(Bitmap bitmap,BlockQueueParams params) {
        params.imageView.setImageBitmap(bitmap);
    }

ImageLoderUtils 是个单例的,创建时会创建一个ThreadManager,ThreadManager管理着线程池。
ThreadManager在创建时就开启了5个线程等待执行任务,当mBlockingQueue.take()取不到数据时线程是阻塞的。当有任务时下载图片,通过Handler去处理UI线程,注意在子线程里Handler要开启一个Looper消息循环啊,isHandlerMsg方法是一个图片错乱校验。

public class ThreadManager {

    private BlockingQueue<BlockQueueParams> mBlockingQueue = new LinkedBlockingQueue();
    private int mThreadNum = 5;
    private LruCache<String, Bitmap> mImageCache;
    private HandlerCallbackImp mHandlerCallbackImp;
    private ConcurrentHashMap<ImageView,String> map = new ConcurrentHashMap<>();

    public ThreadManager(HandlerCallbackImp handlerCallbackImp){
        this.mHandlerCallbackImp = handlerCallbackImp;
        createThread();
        int maxMemory = (int)Runtime.getRuntime().maxMemory();
        int cacheSize = maxMemory/2;
        mImageCache = new LruCache<String, Bitmap>(cacheSize){
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getByteCount();
            }
        };
    }

    private void createThread(){
        for (int i = 0 ; i < mThreadNum ; i++){
            Thread thread = new Thread(new ThreadRunnable());
            thread.start();
        }
    }


    public LruCache<String, Bitmap> getImageCache(){
       return  mImageCache;
    }

    public void putRequestQueue(BlockQueueParams blockQueueParams){
        try {
            mBlockingQueue.put(blockQueueParams);
            map.put(blockQueueParams.imageView,blockQueueParams.imageUrl);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private class ThreadRunnable implements Runnable{

        public String mImageUrl;
        public ImageView mImageView;

        @Override
        public void run() {
            while (true)
            try {
                final BlockQueueParams blockQueueParams = mBlockingQueue.take();
                Log.e("thread","thread name = " + Thread.currentThread().getName());
                final Bitmap bitmap = DownLoadImagesUtils.downloadBitmap(blockQueueParams.imageUrl);
                mImageCache.put(blockQueueParams.imageUrl,bitmap);
                this.mImageUrl = blockQueueParams.imageUrl;
                this.mImageView = blockQueueParams.imageView;
                new Handler(Looper.getMainLooper()).post(new Runnable() {
                    @Override
                    public void run() {
                        if(isHandlerMsg()){
                            mHandlerCallbackImp.handlerMsg(bitmap,blockQueueParams);
                        }
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        private boolean isHandlerMsg(){
            if(map.get(mImageView) == mImageUrl){
                return true;
            }
            return false;
        }
    }
}

下载图片

public class DownLoadImagesUtils {

    public static Bitmap downloadBitmap(String imageUrl) {
        Bitmap bitmap = null;
        HttpURLConnection con = null;
        try {
            URL url = new URL(imageUrl);
            con = (HttpURLConnection) url.openConnection();
            con.setConnectTimeout(5 * 1000);
            con.setReadTimeout(10 * 1000);
            bitmap = BitmapFactory.decodeStream(con.getInputStream());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (con != null) {
                con.disconnect();
            }
        }
        return bitmap;
    }
}

处理handler回调的接口

public interface HandlerCallbackImp {

    public void handlerMsg(Bitmap bitmap,BlockQueueParams params);
}

队列里放的任务参数

public class BlockQueueParams{

    public ImageView imageView;
    public String imageUrl;

    public BlockQueueParams(ImageView imageView, String imageUrl) {
        this.imageView = imageView;
        this.imageUrl = imageUrl;
    }
}

最后使用
ImageLoderUtils imageLoderUtils = ImageLoderUtils.getInstance();
imageLoderUtils.downLoadImages(imageUrl,imageView);

打印了一下线程使用情况发现只是这5个线程在循环工作。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值