在《自己动手写android图片异步加载库》系列的第一篇文章中,主要是学习了使用ReferenceQueue来实现一个内存缓存。在这篇文章中主要是介绍在下载很多图片是怎么控制线程和队列。在这版代码里,加入信号量和队列,可以控制下载任务的顺序、可以控制暂停和结束。
代码A:ImageLoader.java
/** * 图片加载工具类 * * @author qingtian * @blog http://blog.csdn.net/bingoSpunky */ @SuppressLint("HandlerLeak") public class ImageLoader { private int flag = 0; public static int FLAG_FINISHED_INIT_SECOND_THREAD = 0X1; private static final int DEFAULT_THREAD_COUNT = 2; private static final int SUCCESS = 1; private static final int FAILED = 0; // config public int configLoadingImage;// 正在现在时显示的图片id public int configFailedImage;// 下载失败时显示的资源id public Type configType = Type.LIFO;// 队列的调度方式 private ExecutorService threadPool;// 线程池 private Tasks task;// 管理任务的队列 // 图片缓存 private LruCache<String, Bitmap> cache; private Handler mainHandler;// 主线程的handler,修改view private Handler secondHandler;// private volatile Semaphore secondSemaphore;// 信号量控制第二条线程发送的正在执行且没执行完的线程的数量==线程池的数量 public ImageLoader() { this(DEFAULT_THREAD_COUNT); } public ImageLoader(int threadNum) { task = new Tasks(); new Thread() { public void run() { Looper.prepare(); secondHandler = new Handler() { public void handleMessage(android.os.Message msg) { try { secondSemaphore.acquire(); } catch (InterruptedException e) { e.printStackTrace(); } threadPool.execute(task.getTask(configType)); }; }; flag |= FLAG_FINISHED_INIT_SECOND_THREAD; task.mSemaphore.release(); Looper.loop(); }; }.start(); mainHandler = new Handler() { @Override public void handleMessage(Message msg) { ImgBeanHolder holder; switch (msg.what) { case SUCCESS: holder = (ImgBeanHolder) msg.obj; ImageView imageView = holder.imageView; Bitmap bm = holder.bitmap; String uri = holder.uri; Object tag = imageView.getTag(); if (holder!=null&&holder.listener != null) { if (tag != null && tag.toString().equals(uri)) { holder.listener.onSuccess(imageView, true, bm, uri); } else { holder.listener.onSuccess(imageView, false, bm, uri); } LogUtils.d("加载失败 加载图片 uri:"+holder.uri); } break; case FAILED: holder = (ImgBeanHolder) msg.obj; if (holder.listener != null) { holder.listener.onFailed(); LogUtils.d("加载成功 加载图片 uri:"+holder.uri); } break; } } }; threadPool = new ThreadPoolExecutor(threadNum, threadNum, 0, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>()); secondSemaphore = new Semaphore(threadNum); int maxMemory = (int) Runtime.getRuntime().maxMemory(); cache = new LruCache<String, Bitmap>(maxMemory / 8) { // 测量Bitmap的大小 @Override protected int sizeOf(String key, Bitmap value) { return value.getRowBytes() * value.getHeight(); } }; } public void display(ImageView iv, String uri) { display(iv, uri, new SimpleImageLoaderListener()); } public void display(final ImageView iv, final String uri, final ImageLoaderListener imageLoaderListener) throws RuntimeException { if (imageLoaderListener == null) { throw new RuntimeException("imageLoaderListener不能为空"); } iv.setTag(uri); showDefalutImage(iv); task.addTask(flag, new Runnable() { @Override public void run() { LogUtils.d("开始 加载图片 uri:"+uri); Bitmap bm = cache.get(uri); if (bm != null) { LogUtils.d("在内存缓存 加载图片 uri:"+uri); sendMessageToMainHandler(SUCCESS, bm, iv, uri, imageLoaderListener); } else { ImageSize imageSize = ImageViewUtil.getImageViewWidth(iv); LogUtils.d("通过网络 加载图片 uri:"+uri); bm = BitmapUtil.decodeSampledBitmapFromResource(uri, imageSize.width, imageSize.height); // bm = BitmapUtil.getImageBitmap(uri); if (bm != null) { cache.put(uri, bm); sendMessageToMainHandler(SUCCESS, bm, iv, uri, imageLoaderListener); } else { sendMessageToMainHandler(FAILED, bm, iv, uri, imageLoaderListener); } } secondSemaphore.release(); } }); secondHandler.sendEmptyMessage(0x123); } @SuppressWarnings("deprecation") private static BitmapDrawable mBitmapDrawable = new BitmapDrawable(); public void showDefalutImage(ImageView iv){ if (configLoadingImage != 0) { iv.setImageResource(configLoadingImage); }else{ iv.setImageDrawable(mBitmapDrawable); } } public void stop() { task.stop(); } public void restart() { task.start(); } public void cancel() { task.cancel(); } /** * 向主线程的handler发送message */ private void sendMessageToMainHandler(int what, Bitmap bm, ImageView iv, String uri, ImageLoaderListener imageLoaderListener) { ImgBeanHolder holder = new ImgBeanHolder(); holder.bitmap = bm; holder.imageView = iv; holder.uri = uri; holder.listener = imageLoaderListener; Message msg = Message.obtain(); msg.what = what; msg.obj = holder; mainHandler.sendMessage(msg); } public class ImgBeanHolder { Bitmap bitmap; ImageView imageView; String uri; ImageLoaderListener listener; } }
public class Tasks { public boolean starting = true; public enum Type { FIFO, LIFO } /** * 引入一个值为1的信号量,防止mPoolThreadHander未初始化完成 */ public volatile Semaphore mSemaphore = new Semaphore(0); /** * 任务队列 */ private LinkedList<Runnable> mTasks; public Tasks() { mTasks = new LinkedList<Runnable>(); } public synchronized void addTask(int flag, Runnable runnable) { try { // 请求信号量,防止mPoolThreadHander为null if ((flag & ImageLoader.FLAG_FINISHED_INIT_SECOND_THREAD) == 0) mSemaphore.acquire(); } catch (InterruptedException e) { e.printStackTrace(); } mTasks.add(runnable); } public volatile Semaphore startingSemaphore = new Semaphore(0); /** * 取出一个任务 */ public synchronized Runnable getTask(Type type) { if(!starting){ try { LogUtils.d("wait()"); wait(); } catch (InterruptedException e) { e.printStackTrace(); } } if (type == Type.FIFO) { return mTasks.removeFirst(); } else if (type == Type.LIFO) { return mTasks.removeLast(); } return null; } public synchronized void start(){ if(!starting){ starting = true; this.notify(); LogUtils.d("start notify()"); } } public synchronized void stop(){ if(starting){ LogUtils.d("stop()"); starting = false; } } /** * 取消所有任务 */ public synchronized void cancel(){ mTasks.clear(); } }
源码下载