Android list加载图片工具类
总体思路
Handler + looper + message
核心类
package com.base.imagechoose.util; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.support.v4.util.LruCache; import android.util.DisplayMetrics; import android.view.ViewGroup; import android.widget.ImageView; import java.lang.reflect.Field; import java.util.LinkedList; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; /** * 图片加载类 */ public class ImageLoader { private static ImageLoader mInstance; /** * 图片缓存 */ private LruCache<String, Bitmap> mLruCache; private ExecutorService mThreadPool;//线程池, 加载任务 private static final int DAFULT_THREAD_COUNT = 1; //线程数量 /** * 队列调度方式 */ private Type mType = Type.FIFO; /** * 任务队列 */ private LinkedList<Runnable> mTaskQueue; /** * 后台轮询线程 */ private Thread mPoolThread; private Handler mPoolTheadHandler; //信号量同步mPoolTheadHandler private Semaphore mSemaphorePoolTheadHandler = new Semaphore(0); /** * 用Semaphore来控制一个线程执行完才执行下一个 */ private Semaphore mSemaphorePool; //用信号量来达到线程Type规则 /** * UI线程中的Handler */ private Handler mUIHandler; //先进先出 public enum Type { FIFO, FIFI; } private ImageLoader(int threadCount, Type type) { init(threadCount, type); } public static ImageLoader getInstance() { if (mInstance == null) { synchronized (ImageLoader.class) { if (mInstance == null) { mInstance = new ImageLoader(DAFULT_THREAD_COUNT, Type.FIFO); } } } return mInstance; } public static ImageLoader getInstance(int threadCount, Type type) { if (mInstance == null) { synchronized (ImageLoader.class) { if (mInstance == null) { mInstance = new ImageLoader(threadCount, type); } } } return mInstance; } private void init(int threadCount, Type type) { //后台轮询线程 mPoolThread = new Thread(){ @Override public void run() { Looper.prepare(); mPoolTheadHandler = new Handler() { @Override public void handleMessage(Message msg) { //线程池去取出一个任务进行执行 mThreadPool.execute(getTask()); try { //如果信号量为3,到第4个就会阻塞住 mSemaphorePool.acquire(); } catch (InterruptedException e) { e.printStackTrace(); } } }; //释放一个信号量 mSemaphorePoolTheadHandler.release(); Looper.loop(); } }; mPoolThread.start(); //获取应用的最大可用内存 int maxMemory = (int) Runtime.getRuntime().maxMemory(); //设置缓存空间 int cacheMemory = maxMemory/8; //初始化缓存 mLruCache = new LruCache<String, Bitmap>(cacheMemory) { @Override protected int sizeOf(String key, Bitmap value) { //返回内存,value每一行的大小*高度 return value.getRowBytes()*value.getHeight(); } }; //创建线程池 mThreadPool = Executors.newFixedThreadPool(threadCount); //初始化任务队列 mTaskQueue = new LinkedList<>(); mType = type; mSemaphorePool = new Semaphore(threadCount); } /** * 从任务队列取出一个方法 * @return */ private Runnable getTask() { if (mType == Type.FIFO) { return mTaskQueue.removeFirst(); } else { return mTaskQueue.removeLast(); } } /** * 根据path为控件加载图片 * @param path 路径 * @param imageView 控件 */ public void loadImage(final String path, final ImageView imageView) { imageView.setTag(path); if (mUIHandler == null) { mUIHandler = new Handler() { @Override public void handleMessage(Message msg) { //获取得到的图片并在控件上显示 ImgBeanHolder holder = (ImgBeanHolder) msg.obj; //当tag为传入path时才进行赋值 if (holder.imageView.getTag().equals(holder.path)) { holder.imageView.setImageBitmap(holder.bm); } } }; } //根据path在缓存中获取图片 Bitmap bm = getBitmapFromLruCache(path); if (bm != null) { refreashBitmap(path, imageView, bm); } else { //没有图片,添加一个任务 addTasks(new Runnable(){ @Override public void run() { //加载图片 //图片压缩 //1.获得图片需要显示的大小 ImageSize imageSize = getImageViewSize(imageView); //2.压缩图片 Bitmap bm = decodeSampleBitmapFromPath(path, imageSize.width, imageSize.height); //3.把图片加入缓存 addBitmapToLruCache(path,bm); refreashBitmap(path, imageView, bm); //当前任务执行完后释放信号量 mSemaphorePool.release(); } }); } } /** * 发送handler显示图片 * @param path * @param imageView * @param bm */ private void refreashBitmap(String path, ImageView imageView, Bitmap bm) { Message message = new Message(); ImgBeanHolder imgBeanHolder = new ImgBeanHolder(); imgBeanHolder.bm = bm; imgBeanHolder.imageView = imageView; imgBeanHolder.path = path; message.obj = imgBeanHolder; mUIHandler.sendMessage(message); } /** * 将图片放入缓存 * @param path * @param bm */ private void addBitmapToLruCache(String path, Bitmap bm) { if(getBitmapFromLruCache(path) == null) { if (bm != null) { mLruCache.put(path, bm); } } } /** * 添加任务 * @param runnable */ private synchronized void addTasks(Runnable runnable) { //将任务放入任务队列中 mTaskQueue.add(runnable); //发送一个通知去通知后台轮询执行任务 try { if (mPoolTheadHandler == null) mSemaphorePoolTheadHandler.acquire(); } catch (InterruptedException e) { e.printStackTrace(); } mPoolTheadHandler.sendEmptyMessage(0x110); } /** * 根据path在缓存中获取图片 * @param key * @return */ private Bitmap getBitmapFromLruCache(String key) { return mLruCache.get(key); } /** * 根据imageview获取图片需要压缩的宽和高 * @param imageView */ private ImageSize getImageViewSize(ImageView imageView) { ImageSize imageSize = new ImageSize(); DisplayMetrics displayMetrics = imageView.getContext().getResources().getDisplayMetrics(); ViewGroup.LayoutParams lp = imageView.getLayoutParams(); int width = imageView.getWidth(); if (width <= 0) { width = lp.width; //获取imageview在layout中声明的亮度 } if (width <= 0) { width = getImageViewFileValue(imageView, "mMaxWidth"); //检查最大值 } if (width <= 0) { width = displayMetrics.widthPixels; } int height = imageView.getHeight(); if (height <= 0) { height = lp.height; //获取imageview在layout中声明的亮度 } if (height <= 0) { height = getImageViewFileValue(imageView, "mMaxHeight"); //检查最大值 //检查最大值 } if (height <= 0) { height = displayMetrics.heightPixels; } imageSize.width = width; imageSize.height = height; return imageSize; } private static int getImageViewFileValue(Object object,String fileName) { int value = 0; //得到当前ImageView的字段集合 try { Field field = ImageView.class.getDeclaredField(fileName); field.setAccessible(true); int fieldValue = field.getInt(object); if (fieldValue > 0 && fieldValue < Integer.MAX_VALUE) { value = fieldValue; } } catch (Exception e) { e.printStackTrace(); } return value; } /** * 根据图片需要的宽高对图片进行压缩 * @param path * @param width * @param height * @return */ private Bitmap decodeSampleBitmapFromPath(String path, int width, int height) { BitmapFactory.Options options = new BitmapFactory.Options(); //不加入内存 options.inJustDecodeBounds = true; //获取实际的options BitmapFactory.decodeFile(path, options); //用实际的options和需要显示的宽高算出inSampleSize options.inSampleSize = caculateInSampleSize(options, width, height); //使用获取的inSampleSize再次解析图片 //放入内存 options.inJustDecodeBounds = false; Bitmap bitmap = BitmapFactory.decodeFile(path, options); return bitmap; } /** * 用实际的options和需要显示的宽高算出inSampleSize * @param options * @param reqWidth * @param reqHeight * @return */ private int caculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { int width = options.outWidth; int height = options.outHeight; int inSampleSize = 1; if (width > reqHeight || height > reqHeight) { int widthRadio = Math.round(width*1.0f/reqWidth); int heightRadio = Math.round(height*1.0f/reqHeight); inSampleSize = Math.max(widthRadio, heightRadio); } return inSampleSize; } private class ImageSize{ int width; int height; } private class ImgBeanHolder { Bitmap bm; String path; ImageView imageView; } }