Android编程图片加载类ImageLoader定义与用法实例分析
本文实例讲述了Android编程图片加载类ImageLoader定义与用法。分享给大家供大家参考,具体如下:
解析:
1)图片加载使用单例模式,避免多次调用时产生死锁
2)核心对象LruCache
图片加载时先判断缓存里是否有图片,如果有,就使用缓存里的
没有就加载网络的,然后置入缓存
3)使用了线程池ExecutorServicemThreadPool技术
4)使用了Semaphore信号来控制变量按照先后顺序执行,避免空指针的问题
如何使用:
在Adapter里加载图片时
ImageLoader.getInstance.loadImage("http://www.baidu.com/images/kk.jpg",mImageView,true);
源码:
/** *@描述图片加载类 *@项目名称App_News *@包名com.android.news.tools *@类名ImageLoader *@authorchenlin *@date2015-3-7下午7:35:28 *@version1.0 */ publicclassImageLoader{ privatestaticImageLoadermInstance; /** *图片缓存的核心对象 */ privateLruCachemLruCache; /** *线程池 */ privateExecutorServicemThreadPool; privatestaticfinalintDEAFULT_THREAD_COUNT=1; /** *队列的调度方式 */ privateTypemType=Type.LIFO; /** *任务队列 */ privateLinkedList mTaskQueue; /** *后台轮询线程 */ privateThreadmPoolThread; privateHandlermPoolThreadHandler; /** *UI线程中的Handler */ privateHandlermUIHandler; privateSemaphoremSemaphorePoolThreadHandler=newSemaphore(0); privateSemaphoremSemaphoreThreadPool; privatebooleanisDiskCacheEnable=true; privatestaticfinalStringTAG="ImageLoader"; publicenumType{ FIFO,LIFO; } privateImageLoader(intthreadCount,Typetype){ init(threadCount,type); } /** *初始化 * *@paramthreadCount *@paramtype */ privatevoidinit(intthreadCount,Typetype){ initBackThread(); //获取我们应用的最大可用内存 intmaxMemory=(int)Runtime.getRuntime().maxMemory(); intcacheMemory=maxMemory/8; mLruCache=newLruCache (cacheMemory){ @Override protectedintsizeOf(Stringkey,Bitmapvalue){ returnvalue.getRowBytes()*value.getHeight(); } }; //创建线程池 mThreadPool=Executors.newFixedThreadPool(threadCount); mTaskQueue=newLinkedList (); mType=type; mSemaphoreThreadPool=newSemaphore(threadCount); } /** *初始化后台轮询线程 */ privatevoidinitBackThread(){ //后台轮询线程 mPoolThread=newThread(){ @Override publicvoidrun(){ Looper.prepare(); mPoolThreadHandler=newHandler(){ @Override publicvoidhandleMessage(Messagemsg){ //线程池去取出一个任务进行执行 mThreadPool.execute(getTask()); try{ mSemaphoreThreadPool.acquire(); }catch(InterruptedExceptione){ } } }; //释放一个信号量 mSemaphorePoolThreadHandler.release(); Looper.loop(); }; }; mPoolThread.start(); } publicstaticImageLoadergetInstance(){ if(mInstance==null){ synchronized(ImageLoader.class){ if(mInstance==null){ mInstance=newImageLoader(DEAFULT_THREAD_COUNT,Type.LIFO); } } } returnmInstance; } publicstaticImageLoadergetInstance(intthreadCount,Typetype){ if(mInstance==null){ synchronized(ImageLoader.class){ if(mInstance==null){ mInstance=newImageLoader(threadCount,type); } } } returnmInstance; } /** *根据path为imageview设置图片 * *@parampath *@paramimageView */ publicvoidloadImage(finalStringpath,finalImageViewimageView,finalbooleanisFromNet){ imageView.setTag(path); if(mUIHandler==null){ mUIHandler=newHandler(){ publicvoidhandleMessage(Messagemsg){ //获取得到图片,为imageview回调设置图片 ImgBeanHolderholder=(ImgBeanHolder)msg.obj; Bitmapbm=holder.bitmap; ImageViewimageview=holder.imageView; Stringpath=holder.path; //将path与getTag存储路径进行比较 if(imageview.getTag().toString().equals(path)){ imageview.setImageBitmap(bm); } }; }; } //根据path在缓存中获取bitmap Bitmapbm=getBitmapFromLruCache(path); if(bm!=null){ refreashBitmap(path,imageView,bm); }else{ addTask(buildTask(path,imageView,isFromNet)); } } /** *根据传入的参数,新建一个任务 * *@parampath *@paramimageView *@paramisFromNet *@return */ privateRunnablebuildTask(finalStringpath,finalImageViewimageView,finalbooleanisFromNet){ returnnewRunnable(){ @Override publicvoidrun(){ Bitmapbm=null; if(isFromNet){ Filefile=getDiskCacheDir(imageView.getContext(),md5(path)); if(file.exists())//如果在缓存文件中发现 { Log.e(TAG,"findimage:"+path+"indiskcache."); bm=loadImageFromLocal(file.getAbsolutePath(),imageView); }else{ if(isDiskCacheEnable)//检测是否开启硬盘缓存 { booleandownloadState=DownloadImgUtils.downloadImgByUrl(path,file); if(downloadState)//如果下载成功 { Log.e(TAG, "downloadimage:"+path+"todiskcache.pathis" +file.getAbsolutePath()); bm=loadImageFromLocal(file.getAbsolutePath(),imageView); } }else //直接从网络加载 { Log.e(TAG,"loadimage:"+path+"tomemory."); bm=DownloadImgUtils.downloadImgByUrl(path,imageView); } } }else{ bm=loadImageFromLocal(path,imageView); } //3、把图片加入到缓存 addBitmapToLruCache(path,bm); refreashBitmap(path,imageView,bm); mSemaphoreThreadPool.release(); } }; } privateBitmaploadImageFromLocal(finalStringpath,finalImageViewimageView){ Bitmapbm; //加载图片 //图片的压缩 //1、获得图片需要显示的大小 ImageSizeimageSize=ImageSizeUtil.getImageViewSize(imageView); //2、压缩图片 bm=decodeSampledBitmapFromPath(path,imageSize.width,imageSize.height); returnbm; } /** *从任务队列取出一个方法 * *@return */ privateRunnablegetTask(){ if(mType==Type.FIFO){ returnmTaskQueue.removeFirst(); }elseif(mType==Type.LIFO){ returnmTaskQueue.removeLast(); } returnnull; } /** *利用签名辅助类,将字符串字节数组 * *@paramstr *@return */ publicStringmd5(Stringstr){ byte[]digest=null; try{ MessageDigestmd=MessageDigest.getInstance("md5"); digest=md.digest(str.getBytes()); returnbytes2hex02(digest); }catch(NoSuchAlgorithmExceptione){ e.printStackTrace(); } returnnull; } /** *方式二 * *@parambytes *@return */ publicStringbytes2hex02(byte[]bytes){ StringBuildersb=newStringBuilder(); Stringtmp=null; for(byteb:bytes){ //将每个字节与0xFF进行与运算,然后转化为10进制,然后借助于Integer再转化为16进制 tmp=Integer.toHexString(0xFF&b); if(tmp.length()==1)//每个字节8为,转为16进制标志,2个16进制位 { tmp="0"+tmp; } sb.append(tmp); } returnsb.toString(); } privatevoidrefreashBitmap(finalStringpath,finalImageViewimageView,Bitmapbm){ Messagemessage=Message.obtain(); ImgBeanHolderholder=newImgBeanHolder(); holder.bitmap=bm; holder.path=path; holder.imageView=imageView; message.obj=holder; mUIHandler.sendMessage(message); } /** *将图片加入LruCache * *@parampath *@parambm */ protectedvoidaddBitmapToLruCache(Stringpath,Bitmapbm){ if(getBitmapFromLruCache(path)==null){ if(bm!=null) mLruCache.put(path,bm); } } /** *根据图片需要显示的宽和高对图片进行压缩 * *@parampath *@paramwidth *@paramheight *@return */ protectedBitmapdecodeSampledBitmapFromPath(Stringpath,intwidth,intheight){ //获得图片的宽和高,并不把图片加载到内存中 BitmapFactory.Optionsoptions=newBitmapFactory.Options(); options.inJustDecodeBounds=true; BitmapFactory.decodeFile(path,options); options.inSampleSize=ImageSizeUtil.caculateInSampleSize(options,width,height); //使用获得到的InSampleSize再次解析图片 options.inJustDecodeBounds=false; Bitmapbitmap=BitmapFactory.decodeFile(path,options); returnbitmap; } privatesynchronizedvoidaddTask(Runnablerunnable){ mTaskQueue.add(runnable); //if(mPoolThreadHandler==null)wait(); try{ if(mPoolThreadHandler==null) mSemaphorePoolThreadHandler.acquire(); }catch(InterruptedExceptione){ } mPoolThreadHandler.sendEmptyMessage(0x110); } /** *获得缓存图片的地址 * *@paramcontext *@paramuniqueName *@return */ publicFilegetDiskCacheDir(Contextcontext,StringuniqueName){ StringcachePath; if(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())){ cachePath=context.getExternalCacheDir().getPath(); }else{ cachePath=context.getCacheDir().getPath(); } returnnewFile(cachePath+File.separator+uniqueName); } /** *根据path在缓存中获取bitmap * *@paramkey *@return */ privateBitmapgetBitmapFromLruCache(Stringkey){ returnmLruCache.get(key); } privateclassImgBeanHolder{ Bitmapbitmap; ImageViewimageView; Stringpath; } }
相关工具类:
/** *@描述获取图片大小工具类s *@项目名称App_News *@包名com.android.news.util *@类名ImageSizeUtil *@authorchenlin *@date2014-3-7下午7:37:50 *@version1.0 */ publicclassImageSizeUtil{ /** *根据需求的宽和高以及图片实际的宽和高计算SampleSize * *@paramoptions *@paramwidth *@paramheight *@return */ publicstaticintcaculateInSampleSize(Optionsoptions,intreqWidth,intreqHeight){ intwidth=options.outWidth; intheight=options.outHeight; intinSampleSize=1; if(width>reqWidth||height>reqHeight){ intwidthRadio=Math.round(width*1.0f/reqWidth); intheightRadio=Math.round(height*1.0f/reqHeight); inSampleSize=Math.max(widthRadio,heightRadio); } returninSampleSize; } /** *根据ImageView获适当的压缩的宽和高 * *@paramimageView *@return */ publicstaticImageSizegetImageViewSize(ImageViewimageView){ ImageSizeimageSize=newImageSize(); DisplayMetricsdisplayMetrics=imageView.getContext().getResources().getDisplayMetrics(); LayoutParamslp=imageView.getLayoutParams(); intwidth=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; } intheight=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; returnimageSize; } publicstaticclassImageSize{ publicintwidth; publicintheight; } /** *通过反射获取imageview的某个属性值 * *@paramobject *@paramfieldName *@return */ privatestaticintgetImageViewFieldValue(Objectobject,StringfieldName){ intvalue=0; try{ Fieldfield=ImageView.class.getDeclaredField(fieldName); field.setAccessible(true); intfieldValue=field.getInt(object); if(fieldValue>0&&fieldValue更多关于Android相关内容感兴趣的读者可查看本站专题:《Android图形与图像处理技巧总结》、《Android开发入门与进阶教程》、《Android调试技巧与常见问题解决方法汇总》、《Android基本组件用法总结》、《Android视图View技巧总结》、《Android布局layout技巧总结》及《Android控件用法总结》
希望本文所述对大家Android程序设计有所帮助。