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;
/**
*任务队列
*/
privateLinkedListmTaskQueue;
/**
*后台轮询线程
*/
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程序设计有所帮助。