Android图片加载的缓存类
本文为大家分享了Android图片加载的缓存类,供大家参考,具体内容如下
importjava.io.File; importjava.io.FileInputStream; importjava.io.FileNotFoundException; importjava.io.FileOutputStream; importjava.io.IOException; importjava.io.InputStream; importjava.lang.ref.SoftReference; importjava.net.HttpURLConnection; importjava.net.URL; importjava.util.LinkedHashMap; importjava.util.concurrent.ConcurrentHashMap; importjava.util.concurrent.ExecutorService; importjava.util.concurrent.Executors; importandroid.graphics.Bitmap; importandroid.graphics.BitmapFactory; importandroid.os.Build; importandroid.os.Handler; importandroid.text.TextUtils; /** *图片加载器,主要功能是从网络中下载图片并缓存。这里之所以另写一个功能类似重复的原因是之前旧的图片加载逻辑感觉非常复杂,我这里写个轻量级的 * *@authorH3c * */ publicclassImageLoaderEngine{ publicstaticfinalintLOAD_IMG_SUCCESS=2010; privatefinalintMAX_CAPACITY=Build.VERSION.SDK_INT>Build.VERSION_CODES.GINGERBREAD_MR1?50:10;//一级缓存缓存图片数 privatestaticImageLoaderEngineinstance; privatestaticHandlermHandler; privateExecutorServicepool;//后台线程池 //这里用LinkedHashMap不用LruCache的原因是LruCache直接申请内存大小而不是图片个数。此App已经有一个全局的LruCache了,重复申请内存大小对应用不利 privateLinkedHashMap<String,Bitmap>mFirstLevelCache;//<momentId>一级缓存,硬链接bitmap,只保留最近用的图片。 privateConcurrentHashMap<String,SoftReference<Bitmap>>mSecondLevelCache;//<momentId> publicstaticImageLoaderEnginegetInstance(Handlerhandler){ if(instance==null){ instance=newImageLoaderEngine(); } if(handler!=null){ mHandler=handler; } returninstance; } privateImageLoaderEngine(){ pool=Executors.newFixedThreadPool(4);//默认线程池大小为6 initCache(); } privatevoidinitCache(){ mFirstLevelCache=newLinkedHashMap<String,Bitmap>(MAX_CAPACITY/2, 0.75f,true){ privatestaticfinallongserialVersionUID=1L; protectedbooleanremoveEldestEntry(Entry<String,Bitmap>eldest){ if(size()>MAX_CAPACITY){//超过一级缓存大小后会挪到二级缓存中 mSecondLevelCache.put(eldest.getKey(), newSoftReference<Bitmap>(eldest.getValue())); returntrue; } returnfalse; }; }; mSecondLevelCache=newConcurrentHashMap<String,SoftReference<Bitmap>>();//<momentId> } /** *移除缓存 *@paramkey */ publicvoiddeleteCacheByKey(Stringkey){ StringsdCacheingPath=IOHelper.getCachedPicturePath( Global.packageName,key); StringsdCacheedPath=sdCacheingPath+".png"; Filefile=newFile(sdCacheingPath); if(file.exists()){ file.delete(); } file=newFile(sdCacheedPath); if(file.exists()){ file.delete(); } mFirstLevelCache.remove(key); mSecondLevelCache.remove(key); } /** *释放资源 */ publicvoidrecycleImageLoader(){ newThread(newRunnable(){ @Override publicvoidrun(){ if(pool!=null){ pool.shutdownNow(); } if(mFirstLevelCache!=null){ for(Bitmapbmp:mFirstLevelCache.values()){ if(bmp!=null){ bmp.recycle(); bmp=null; } } mFirstLevelCache.clear(); mFirstLevelCache=null; } if(mSecondLevelCache!=null){ mSecondLevelCache.clear(); } mHandler=null; } }).start(); } /** *后台请求图片 * *@paramitem */ publicvoidloadImageByMoment(finalNMomentmoment,StringphotoTag){ if(moment.isPicture() ||moment.isVideo()){ Stringid=moment.id+photoTag; loadImageByUrl(id+"",moment.getPicture(Global.widthPixels/3*2),moment.orientation); } } /** *后台请求图片 *@paramkey *@paramurl */ publicvoidloadImageByUrl(finalStringkey,finalStringurl,finalintorientation){ pool.submit(newRunnable(){ publicvoidrun(){ LogHelper.e("ImageLoaderEngine","从网络中下载"); //如果内存中有就算了 if(mFirstLevelCache.get(key)!=null ||mSecondLevelCache.get(key)!=null){//如果图片已经缓存了 LogHelper.e("ImageLoaderEngine","下载图片错误1"); return; } //如果SD卡缓存中有就算了 finalStringsdCacheingPath=IOHelper.getCachedPicturePath( Global.packageName,key); FilecacheingFile=newFile(sdCacheingPath); if(cacheingFile.exists()){//如果正在缓存就算了 longcurrentTime=System.currentTimeMillis(); if((currentTime-cacheingFile.lastModified())>2*60*1000){ LogHelper.e("ImageLoaderEngine","2分钟都还没下载完,准备删除它.."+currentTime+"="+cacheingFile.lastModified()); cacheingFile.delete(); }else{ getBitmapFromNetworkAndAddToMemory(url,key,orientation); LogHelper.e("ImageLoaderEngine","第二次进来应该走这里.."); return; } } StringsdCacheedPath=sdCacheingPath+".png";//缓存完成后会改名字,否则会导致缓存错误,图片变黑 FilecacheedFile=newFile(sdCacheedPath); if(cacheedFile.exists()){//如果缓存了就算了 LogHelper.e("ImageLoaderEngine","下载图片错误2"); return; } getBitmapFromNetworkAndAddToMemory(url,key,orientation); } }); } privatevoidgetBitmapFromNetworkAndAddToMemory(Stringurl,Stringkey,intorientation){ Bitmapbmp=getBitmapFromUrl(url); if(bmp!=null){ LogHelper.e("ImageLoaderEngine","下载网络图片成功"); if(key.endsWith("_DetailDaily")){ bmp=scaledBitmap(bmp,Global.getThumbWidth()); } if(orientation!=0){ mFirstLevelCache.put(key,ViewHelper.rotateBitmap(orientation,bmp));//从网络下载后直接显示 }else{ mFirstLevelCache.put(key,bmp);//从网络下载后直接显示 } if(mHandler!=null){ mHandler.removeMessages(LOAD_IMG_SUCCESS); mHandler.sendEmptyMessageDelayed( LOAD_IMG_SUCCESS,600);//延时提示没有数据了 } finalStringsdCacheingPath=IOHelper.getCachedPicturePath( Global.packageName,key); saveBitmapToFile(sdCacheingPath,bmp); }else{ LogHelper.e("ImageLoaderEngine","下载网络图片失败..."); } } /** *直接从网络中获取 *@paramurl *@return */ publicBitmapgetBitmapFromUrl(Stringurl){ URLmyFileUrl=null; Bitmapbitmap=null; InputStreamis=null; try{ if(!UIUtils.isNetworkAvailable(MyApplication.getInstance())){ returnnull; } myFileUrl=newURL(url); HttpURLConnectionconn=(HttpURLConnection)myFileUrl .openConnection(); conn.setDoInput(true); conn.connect(); is=conn.getInputStream(); bitmap=BitmapFactory.decodeStream(is); }catch(Exceptione){ try{ if(is!=null){ is.close(); } }catch(IOExceptione1){ e1.printStackTrace(); } e.printStackTrace(); } returnbitmap; } publicBitmapgetImageInMemory(NMomentmoment){ returngetImageInMemory(moment,""); } /** *新增接口,可以根据tag重新标识Moment,这样可以扩展应用场景,比如首页需要大图,进入相集页需要小图 *@parammoment *@paramphotoTag *@return */ publicBitmapgetImageInMemory(NMomentmoment,StringphotoTag){ Stringid=moment.id+photoTag; Bitmapbmp=null; //1.从一级缓存中获取 bmp=getFromFirstLevelCache(id); if(bmp!=null&&!bmp.isRecycled()){ LogHelper.e("ImageLoaderEngine","一级缓存获取:"+id); returnbmp; } //2.从二级缓存中获取 bmp=getFromSecondLevelCache(id); if(bmp!=null&&!bmp.isRecycled()){ LogHelper.e("ImageLoaderEngine","二级缓存获取:"+id); returnbmp; } if(bmp!=null&&bmp.isRecycled()){ returnnull; }else{ returnbmp; } } publicvoidsetImage(Stringkey,Bitmappicture){ mFirstLevelCache.put(key,picture); } /** *获取图片 */ publicBitmapgetImage(NMomentmoment){ returngetImage(moment,""); } publicBitmapgetImage(NMomentmoment,StringphotoTag){ Stringid=moment.id+photoTag; Bitmapbmp=null; //1.从一级缓存中获取 bmp=getFromFirstLevelCache(id); if(bmp!=null&&!bmp.isRecycled()){ LogHelper.e("ImageLoaderEngine","一级缓存获取:"+id); returnbmp; } //2.从二级缓存中获取 bmp=getFromSecondLevelCache(id); if(bmp!=null&&!bmp.isRecycled()){ LogHelper.e("ImageLoaderEngine","二级缓存获取:"+id); returnbmp; } //3.从SD卡缓存中获取 bmp=getFromSDCache(moment,photoTag); if(bmp!=null&&!bmp.isRecycled()){ LogHelper.e("ImageLoaderEngine","SD卡缓存获取:"+id); returnbmp; } //4.从网络中获取 loadImageByMoment(moment,photoTag); //LogHelper.e("ImageLoaderEngine","本地获取图片失败:"+moment.id+"="+moment.getPicture()); if(bmp!=null&&bmp.isRecycled()){ returnnull; }else{ returnbmp; } } publicBitmapgetImage(Stringkey,Stringurl){ Bitmapbmp=null; //1.从一级缓存中获取 bmp=getFromFirstLevelCache(key); if(bmp!=null&&!bmp.isRecycled()){ returnbmp; } //2.从二级缓存中获取 bmp=getFromSecondLevelCache(key); if(bmp!=null&&!bmp.isRecycled()){ returnbmp; } //3.从SD卡缓存中获取 bmp=getFromSDCacheByKey(key,0); if(bmp!=null&&!bmp.isRecycled()){ returnbmp; } //4.从网络中获取 loadImageByUrl(key,url,0); if(bmp!=null&&bmp.isRecycled()){ returnnull; }else{ returnbmp; } } /** *一级缓存获取图片 * *@paramimgId *@return */ privateBitmapgetFromFirstLevelCache(StringimgId){ Bitmapbitmap=null; synchronized(mFirstLevelCache){ bitmap=mFirstLevelCache.get(imgId); if(bitmap!=null){ mFirstLevelCache.remove(imgId); mFirstLevelCache.put(imgId,bitmap); } } returnbitmap; } /** *二级缓存获取图片 * *@paramurl *@return */ privateBitmapgetFromSecondLevelCache(StringimgId){ Bitmapbitmap=null; SoftReference<Bitmap>softReference=mSecondLevelCache.get(imgId); if(softReference!=null){ bitmap=softReference.get(); if(bitmap==null){ mSecondLevelCache.remove(imgId); } } returnbitmap; } /** *从SD卡缓存获取图片,并放入一级缓存中 * *@parammoment *@return *@throwsIOException */ privateBitmapgetFromSDCache(finalNMomentmoment,finalStringphotoTag){ Bitmapdrawable=null; Stringid=moment.id+photoTag; StringsdCacheingPath=IOHelper.getCachedPicturePath(Global.packageName, id); StringsdCacheedPath=sdCacheingPath+".png"; if(moment.isLocal){ if(moment.isVideo()){ //获取本地路径 sdCacheedPath=moment.getPicture(Global.widthPixels/3*2); }else{ sdCacheedPath=moment.local_res_path; } } FilecacheFile=newFile(sdCacheedPath); if(!cacheFile.exists()){//如果没有缓存完成就退出 LogHelper.e("ImageLoaderEngine","找不到缓存文件:"+sdCacheedPath); if(!TextUtils.isEmpty(moment.local_res_path)){//如果本地有图片,就先用本地图片代替 sdCacheedPath=moment.local_res_path; cacheFile=newFile(sdCacheedPath); if(cacheFile.exists()&&!GlobalData.PHONE_MANUFACTURER.equalsIgnoreCase("samsung")){ LogHelper.e("ImageLoaderEngine","AK47...:"+GlobalData.PHONE_MANUFACTURER);//先从本地找替代图片.. newThread(newRunnable(){//从网络下载 @Override publicvoidrun(){ loadImageByMoment(moment,photoTag); } }).start(); returngetFitPhoto(sdCacheedPath,moment,cacheFile); }else{ returnnull; } }else{ returnnull; } } drawable=getFitPhoto(sdCacheedPath,moment,cacheFile); if(drawable!=null){ if(moment.orientation!=0){ drawable=ViewHelper .rotateBitmap(moment.orientation,drawable); } if(mFirstLevelCache!=null){ mFirstLevelCache.put(id,drawable); } }else{ cacheFile.delete(); } returndrawable; } privateBitmapgetFitPhoto(StringsdCacheedPath,NMomentmoment,FilecacheFile){ FileInputStreamfs=null; Bitmapresult; try{ BitmapFactory.Optionsoptions=newBitmapFactory.Options(); options.inJustDecodeBounds=true; BitmapFactory.decodeFile(sdCacheedPath,options); inthRatio=(int)Math.ceil(options.outHeight /(float)moment.picture_height);//算高度 intwRatio=(int)Math.ceil(options.outWidth /(float)Global.widthPixels);//算宽度 if(hRatio>1||wRatio>1){ if(hRatio>wRatio){ options.inSampleSize=hRatio; }else options.inSampleSize=wRatio; } options.inPurgeable=true; options.inInputShareable=true; options.inDither=false; options.inJustDecodeBounds=false; try{ fs=newFileInputStream(cacheFile); }catch(FileNotFoundExceptione){ e.printStackTrace(); } result=BitmapFactory.decodeFileDescriptor(fs.getFD(),null, options); }catch(Exceptione){ thrownewRuntimeException(e); }finally{ if(fs!=null){ try{ fs.close(); }catch(IOExceptione){ e.printStackTrace(); } } } returnresult; } privateBitmapgetFromSDCacheByKey(Stringkey,intorientation){ Bitmapdrawable=null; FileInputStreamfs=null; StringsdCacheedPath=IOHelper.getCachedPicturePath( Global.packageName,key)+".png"; FilecacheFile=newFile(sdCacheedPath); if(!cacheFile.exists()){//如果没有缓存完成就退出 returnnull; } try{ BitmapFactory.Optionsoptions=newBitmapFactory.Options(); options.inJustDecodeBounds=true; BitmapFactory.decodeFile(sdCacheedPath,options); intwRatio=(int)Math.ceil(options.outWidth /(float)Global.widthPixels);//算宽度 options.inSampleSize=wRatio; options.inPurgeable=true; options.inInputShareable=true; options.inDither=false; options.inJustDecodeBounds=false; try{ fs=newFileInputStream(cacheFile); }catch(FileNotFoundExceptione){ e.printStackTrace(); } drawable=BitmapFactory.decodeFileDescriptor(fs.getFD(),null, options); if(drawable!=null){ if(orientation!=0){ drawable=ViewHelper.rotateBitmap(orientation,drawable); } mFirstLevelCache.put(key,drawable); }else{ cacheFile.delete(); } }catch(Exceptione){ thrownewRuntimeException(e); }finally{ if(fs!=null){ try{ fs.close(); }catch(IOExceptione){ e.printStackTrace(); } } } returndrawable; } /** *创建一个灰色的默认图 *@parammoment *@return */ publicBitmapgetDefaultBitmap(NMomentmoment){ returnImageHelper.createBitmap(moment.picture_width,moment.picture_height, R.color.image_bg_daily); } /** *保存Bitmap文件到sd卡,传入jpg结尾的路径 *@paramfilePath *@parammBitmap */ publicvoidsaveBitmapToFile(StringfilePath,BitmapmBitmap){ try{ Filefile=newFile(filePath); if(!file.getParentFile().exists()){ file.getParentFile().mkdirs(); } if(file.exists()&&file.length()>0){ longcurrentTime=System.currentTimeMillis(); if((currentTime-file.lastModified())>2*60*1000){ LogHelper.e("ImageLoaderEngine", "2分钟都还没下载完,准备删除它.."+currentTime+"=" +file.lastModified()); file.delete(); }else{ return; } }else{ file.createNewFile(); } FileOutputStreamfOut=null; fOut=newFileOutputStream(file); mBitmap.compress(Bitmap.CompressFormat.JPEG,80,fOut); fOut.flush(); fOut.close(); file.renameTo(newFile(filePath+".png")); }catch(Exceptione){ e.printStackTrace(); LogHelper.e("ImageLoaderEngine","保存图片错误:"+e); } LogHelper.e("ImageLoaderEngine","保存网络图片成功"+filePath+".png"); } /** *保存文件至缓存,这里重写而不用IOHelper里面的原因是IOHelper里面过于复杂 * *@paramurl *@paramfilePath *@return */ publicbooleansaveUrlBitmapToFile(Stringurl,StringfilePath){ if(TextUtils.isEmpty(filePath)){ returnfalse; } FileiconFile=newFile(filePath); if(iconFile.getParentFile()==null){ returnfalse; } if(!iconFile.getParentFile().exists()){ iconFile.getParentFile().mkdirs(); } if(iconFile.exists()&&iconFile.length()>0){ longcurrentTime=System.currentTimeMillis(); if((currentTime-iconFile.lastModified())>2*60*1000){ LogHelper.e("ImageLoaderEngine","2分钟都还没下载完,准备删除它.."+currentTime+"="+iconFile.lastModified()); iconFile.delete(); }else{ returntrue; } } FileOutputStreamfos=null; InputStreamis=null; try{ fos=newFileOutputStream(filePath); is=newURL(url).openStream(); intdata=is.read(); while(data!=-1){ fos.write(data); data=is.read(); } }catch(IOExceptione){ LogHelper.e("ImageLoaderEngine","ImageLoaderEngine下载图片错误"+e); iconFile.delete(); e.printStackTrace(); returnfalse; }finally{ try{ if(is!=null){ is.close(); } if(fos!=null){ fos.close(); } }catch(IOExceptione){ e.printStackTrace(); } } iconFile.renameTo(newFile(filePath+".png")); returntrue; } /** *缩放bitmap *@parambmp *@paramscaledValue缩放值 *@return */ publicBitmapscaledBitmap(Bitmapbmp,intscaledValue){ intbmpWidth=bmp.getWidth(); intbmpHeight=bmp.getHeight(); if(bmpWidth>=bmpHeight){//横图 bmpWidth=(bmpWidth*scaledValue/bmpHeight); bmpHeight=scaledValue; }else{ bmpHeight=(bmpHeight*scaledValue/bmpWidth); bmpWidth=scaledValue; } BitmapscaledBmp=Bitmap.createScaledBitmap(bmp,bmpWidth,bmpHeight,true); bmp.recycle(); bmp=null; returnscaledBmp; } }
以上就是一个完整的Android图片加载缓存类,希望对大家的学习有所帮助。