
本文实例讲述了AndroID编程图片加载类ImageLoader定义与用法。分享给大家供大家参考,具体如下:
解析:
1)图片加载使用单例模式,避免多次调用时产生死锁
2)核心对象 LruCache
图片加载时先判断缓存里是否有图片,如果有,就使用缓存里的
没有就加载网络的,然后置入缓存
3)使用了线程池ExecutorService mThreadPool技术
4)使用了Semaphore 信号来控制变量按照先后顺序执行,避免空指针的问题
如何使用:
在Adapter里加载图片时
复制代码 代码如下:ImageLoader.getInstance.loadImage("http://www.baIDu.com/images/kk.jpg",mImageVIEw,true);
源码:
/** * @描述 图片加载类 * @项目名称 App_News * @包名 com.androID.news.tools * @类名 ImageLoader * @author chenlin * @date 2015-3-7 下午7:35:28 * @version 1.0 */public class ImageLoader { private static ImageLoader mInstance; /** * 图片缓存的核心对象 */ private LruCache<String,Bitmap> mLruCache; /** * 线程池 */ private ExecutorService mThreadPool; private static final int DEAFulT_THREAD_COUNT = 1; /** * 队列的调度方式 */ private Type mType = Type.liFO; /** * 任务队列 */ private linkedList<Runnable> mTaskQueue; /** * 后台轮询线程 */ private Thread mPoolThread; private Handler mPoolThreadHandler; /** * UI线程中的Handler */ private Handler mUIHandler; private Semaphore mSemaphorePoolThreadHandler = new Semaphore(0); private Semaphore mSemaphoreThreadPool; private boolean isdiskCacheEnable = true; private static final String TAG = "ImageLoader"; public enum Type { FIFO,liFO; } private ImageLoader(int threadCount,Type type) { init(threadCount,type); } /** * 初始化 * * @param threadCount * @param type */ private voID init(int threadCount,Type type) { initBackThread(); // 获取我们应用的最大可用内存 int maxMemory = (int) Runtime.getRuntime().maxMemory(); int cacheMemory = maxMemory / 8; mLruCache = new LruCache<String,Bitmap>(cacheMemory) { @OverrIDe protected int sizeOf(String key,Bitmap value) { return value.getRowBytes() * value.getHeight(); } }; // 创建线程池 mThreadPool = Executors.newFixedThreadPool(threadCount); mTaskQueue = new linkedList<Runnable>(); mType = type; mSemaphoreThreadPool = new Semaphore(threadCount); } /** * 初始化后台轮询线程 */ private voID initBackThread() { // 后台轮询线程 mPoolThread = new Thread() { @OverrIDe public voID run() { Looper.prepare(); mPoolThreadHandler = new Handler() { @OverrIDe public voID handleMessage(Message msg) { // 线程池去取出一个任务进行执行 mThreadPool.execute(getTask()); try { mSemaphoreThreadPool.acquire(); } catch (InterruptedException e) { } } }; // 释放一个信号量 mSemaphorePoolThreadHandler.release(); Looper.loop(); }; }; mPoolThread.start(); } public static ImageLoader getInstance() { if (mInstance == null) { synchronized (ImageLoader.class) { if (mInstance == null) { mInstance = new ImageLoader(DEAFulT_THREAD_COUNT,Type.liFO); } } } 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; } /** * 根据path为imagevIEw设置图片 * * @param path * @param imageVIEw */ public voID loadImage(final String path,final ImageVIEw imageVIEw,final boolean isFromNet) { imageVIEw.setTag(path); if (mUIHandler == null) { mUIHandler = new Handler() { public voID handleMessage(Message msg) { // 获取得到图片,为imagevIEw回调设置图片 imgBeanHolder holder = (imgBeanHolder) msg.obj; Bitmap bm = holder.bitmap; ImageVIEw imagevIEw = holder.imageVIEw; String path = holder.path; // 将path与getTag存储路径进行比较 if (imagevIEw.getTag().toString().equals(path)) { imagevIEw.setimageBitmap(bm); } }; }; } // 根据path在缓存中获取bitmap Bitmap bm = getBitmapFromLruCache(path); if (bm != null) { refreashBitmap(path,imageVIEw,bm); } else { addTask(buildTask(path,isFromNet)); } } /** * 根据传入的参数,新建一个任务 * * @param path * @param imageVIEw * @param isFromNet * @return */ private Runnable buildTask(final String path,final boolean isFromNet) { return new Runnable() { @OverrIDe public voID run() { Bitmap bm = null; if (isFromNet) { file file = getdiskCacheDir(imageVIEw.getContext(),md5(path)); if (file.exists())// 如果在缓存文件中发现 { Log.e(TAG,"find image :" + path + " in disk cache ."); bm = loadImageFromLocal(file.getabsolutePath(),imageVIEw); } else { if (isdiskCacheEnable)// 检测是否开启硬盘缓存 { boolean downloadState = DownloadimgUtils.downloadimgByUrl(path,file); if (downloadState)// 如果下载成功 { Log.e(TAG,"download image :" + path + " to disk cache . path is " + file.getabsolutePath()); bm = loadImageFromLocal(file.getabsolutePath(),imageVIEw); } } else // 直接从网络加载 { Log.e(TAG,"load image :" + path + " to memory."); bm = DownloadimgUtils.downloadimgByUrl(path,imageVIEw); } } } else { bm = loadImageFromLocal(path,imageVIEw); } // 3、把图片加入到缓存 addBitmapTolruCache(path,bm); refreashBitmap(path,bm); mSemaphoreThreadPool.release(); } }; } private Bitmap loadImageFromLocal(final String path,final ImageVIEw imageVIEw) { Bitmap bm; // 加载图片 // 图片的压缩 // 1、获得图片需要显示的大小 ImageSize imageSize = ImageSizeUtil.getimageVIEwSize(imageVIEw); // 2、压缩图片 bm = decodeSampledBitmapFromPath(path,imageSize.wIDth,imageSize.height); return bm; } /** * 从任务队列取出一个方法 * * @return */ private Runnable getTask() { if (mType == Type.FIFO) { return mTaskQueue.removeFirst(); } else if (mType == Type.liFO) { return mTaskQueue.removeLast(); } return null; } /** * 利用签名辅助类,将字符串字节数组 * * @param str * @return */ public String md5(String str) { byte[] digest = null; try { MessageDigest md = MessageDigest.getInstance("md5"); digest = md.digest(str.getBytes()); return bytes2hex02(digest); } catch (NoSuchAlgorithmException e) { e.printstacktrace(); } return null; } /** * 方式二 * * @param bytes * @return */ public String bytes2hex02(byte[] bytes) { StringBuilder sb = new StringBuilder(); String tmp = null; for (byte b : bytes) { // 将每个字节与0xFF进行与运算,然后转化为10进制,然后借助于Integer再转化为16进制 tmp = Integer.toHexString(0xFF & b); if (tmp.length() == 1)// 每个字节8为,转为16进制标志,2个16进制位 { tmp = "0" + tmp; } sb.append(tmp); } return sb.toString(); } private voID refreashBitmap(final String path,Bitmap bm) { Message message = Message.obtain(); imgBeanHolder holder = new imgBeanHolder(); holder.bitmap = bm; holder.path = path; holder.imageVIEw = imageVIEw; message.obj = holder; mUIHandler.sendMessage(message); } /** * 将图片加入LruCache * * @param path * @param bm */ protected voID addBitmapTolruCache(String path,Bitmap bm) { if (getBitmapFromLruCache(path) == null) { if (bm != null) mLruCache.put(path,bm); } } /** * 根据图片需要显示的宽和高对图片进行压缩 * * @param path * @param wIDth * @param height * @return */ protected Bitmap decodeSampledBitmapFromPath(String path,int wIDth,int height) { // 获得图片的宽和高,并不把图片加载到内存中 BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodefile(path,options); options.inSampleSize = ImageSizeUtil.caculateInSampleSize(options,wIDth,height); // 使用获得到的InSampleSize再次解析图片 options.inJustDecodeBounds = false; Bitmap bitmap = BitmapFactory.decodefile(path,options); return bitmap; } private synchronized voID addTask(Runnable runnable) { mTaskQueue.add(runnable); // if(mPoolThreadHandler==null)wait(); try { if (mPoolThreadHandler == null) mSemaphorePoolThreadHandler.acquire(); } catch (InterruptedException e) { } mPoolThreadHandler.sendEmptyMessage(0x110); } /** * 获得缓存图片的地址 * * @param context * @param unique@R_403_6889@ * @return */ public file getdiskCacheDir(Context context,String unique@R_403_6889@) { String cachePath; if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { cachePath = context.getExternalCacheDir().getPath(); } else { cachePath = context.getCacheDir().getPath(); } return new file(cachePath + file.separator + unique@R_403_6889@); } /** * 根据path在缓存中获取bitmap * * @param key * @return */ private Bitmap getBitmapFromLruCache(String key) { return mLruCache.get(key); } private class imgBeanHolder { Bitmap bitmap; ImageVIEw imageVIEw; String path; }}相关工具类:
/** * @描述 获取图片大小工具类s * @项目名称 App_News * @包名 com.androID.news.util * @类名 ImageSizeUtil * @author chenlin * @date 2014-3-7 下午7:37:50 * @version 1.0 */public class ImageSizeUtil { /** * 根据需求的宽和高以及图片实际的宽和高计算SampleSize * * @param options * @param wIDth * @param height * @return */ public static int caculateInSampleSize(Options options,int reqWIDth,int reqHeight) { int wIDth = options.outWIDth; int height = options.outHeight; int inSampleSize = 1; if (wIDth > reqWIDth || 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; } /** * 根据ImageVIEw获适当的压缩的宽和高 * * @param imageVIEw * @return */ public static ImageSize getimageVIEwSize(ImageVIEw imageVIEw) { ImageSize imageSize = new ImageSize(); displayMetrics displayMetrics = imageVIEw.getContext().getResources().getdisplayMetrics(); LayoutParams lp = imageVIEw.getLayoutParams(); int wIDth = imageVIEw.getWIDth();// 获取imagevIEw的实际宽度 if (lp != null) { if (wIDth <= 0) { wIDth = lp.wIDth;// 获取imagevIEw在layout中声明的宽度 } } if (wIDth <= 0) { // wIDth = imageVIEw.getMaxWIDth();// 检查最大值 wIDth = getimageVIEwFIEldValue(imageVIEw,"mMaxWIDth"); } if (wIDth <= 0) { wIDth = displayMetrics.wIDthPixels; } int height = imageVIEw.getHeight();// 获取imagevIEw的实际高度 if (lp != null) { if (height <= 0) { height = lp.height;// 获取imagevIEw在layout中声明的宽度 } } if (height <= 0) { height = getimageVIEwFIEldValue(imageVIEw,"mMaxHeight");// 检查最大值 } if (height <= 0) { height = displayMetrics.heightPixels; } imageSize.wIDth = wIDth; imageSize.height = height; return imageSize; } public static class ImageSize { public int wIDth; public int height; } /** * 通过反射获取imagevIEw的某个属性值 * * @param object * @param fIEld@R_403_6889@ * @return */ private static int getimageVIEwFIEldValue(Object object,String fIEld@R_403_6889@) { int value = 0; try { FIEld fIEld = ImageVIEw.class.getDeclaredFIEld(fIEld@R_403_6889@); fIEld.setAccessible(true); int fIEldValue = fIEld.getInt(object); if (fIEldValue > 0 && fIEldValue < Integer.MAX_VALUE) { value = fIEldValue; } } catch (Exception e) { } return value; }}更多关于AndroID相关内容感兴趣的读者可查看本站专题:《Android图形与图像处理技巧总结》、《Android开发入门与进阶教程》、《Android调试技巧与常见问题解决方法汇总》、《Android基本组件用法总结》、《Android视图View技巧总结》、《Android布局layout技巧总结》及《Android控件用法总结》
希望本文所述对大家AndroID程序设计有所帮助。
总结以上是内存溢出为你收集整理的Android编程图片加载类ImageLoader定义与用法实例分析全部内容,希望文章能够帮你解决Android编程图片加载类ImageLoader定义与用法实例分析所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)