android 网络图片双缓存
本文转自:http://blog.csdn.net/a79412906/article/details/10180583
Android每次加载图片很浪费时间。所以设计了一个图片缓存技术来解决每次android手机加载图片的问题
内存的读取速度是最快的,然后是文件的读取速度,最后是网络资源的读取
既然内存的读取时间最快,我们好好利用内存资源。将内存再分两层缓存
强引用缓存不会轻易被回收,来保存常用数据,不常用的资源放入软引用缓存中。
对于硬引用和软引用的介绍:
⑴强引用(StrongReference)
强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。
⑵软引用(SoftReference)
如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存
1,对于强引用和软引用的使用,我们首先去强引用缓存中去找图片资源,当没有发现时,就去软引用缓存中。当强引用的超额时,将最后使用的资源放入软引用缓存中,使用到软引用的资源时,则将资源重新放回强引用缓存池中。
2,内存缓存池中找不到,就去文件中查找,
3,再找不到就只好去网络上下载了,下载到以后,分别将资源放入文件缓存和内存缓存中
Android对于InputStream流有个小bug在慢速网络的情况下可能产生中断,可以考虑重写FilterInputStream处理 skip方法来解决这个bug。BitmapFactory类的decodeStream方法在网络超时或较慢的时候无法获取完整的数据,这里我们通 过继承FilterInputStream类的skip方法来强制实现flush流中的数据,主要原理就是检查是否到文件末端,告诉http类是否继续。
staticclassFlushedInputStreamextendsFilterInputStream{
publicFlushedInputStream(InputStreaminputStream){
super(inputStream);
}
@Override
publiclongskip(longn)throwsIOException{
longtotalBytesSkipped=0L;
while(totalBytesSkipped<n){
longbytesSkipped=in.skip(n-totalBytesSkipped);
if(bytesSkipped==0L){
intb=read();
if(b<0){
break;//wereachedEOF
}else{
bytesSkipped=1;//wereadonebyte
}
}
totalBytesSkipped+=bytesSkipped;
}
returntotalBytesSkipped;
}
}
主界面读取图片
[java] view plain copy- publicclassMainActivityextendsActivity{
- privateImageMemoryCachememoryCache;
- privateImageFileCachefileCache;
- privateImageViewimageView;
- @Override
- protectedvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- memoryCache=newImageMemoryCache(this);
- fileCache=newImageFileCache();
- imageView=(ImageView)findViewById(R.id.img);
- Bitmapb=getBitmap("http://f.hiphotos.baidu.com/album/w%3D2048/sign=7aa167f79f2f07085f052d00dd1cb999/472309f7905298228f794c7bd6ca7bcb0b46d4c4.jpg");
- imageView.setImageBitmap(b);
- }
- publicBitmapgetBitmap(Stringurl){
- //从内存缓存中获取图片
- Bitmapresult=memoryCache.getBitmapFromCache(url);
- if(result==null){
- //文件缓存中获取
- result=fileCache.getImage(url);
- if(result==null){
- //从网络获取
- result=ImageGetFromHttp.downloadBitmap(url);
- if(result!=null){
- fileCache.saveBitmap(result,url);
- memoryCache.addBitmapToCache(url,result);
- }
- }else{
- //添加到内存缓存
- memoryCache.addBitmapToCache(url,result);
- }
- }
- returnresult;
- }
- }
内存中读取
[java] view plain copy- publicclassImageMemoryCache{
- /**
- *从内存读取数据速度是最快的,为了更大限度使用内存,这里使用了两层缓存。
- *硬引用缓存不会轻易被回收,用来保存常用数据,不常用的转入软引用缓存。
- */
- privatestaticfinalintSOFT_CACHE_SIZE=15;//软引用缓存容量
- privatestaticLruCache<String,Bitmap>mLruCache;//硬引用缓存
- privatestaticLinkedHashMap<String,SoftReference<Bitmap>>mSoftCache;//软引用缓存
- publicImageMemoryCache(Contextcontext){
- intmemClass=((ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();
- intcacheSize=1024*1024*memClass/4;//硬引用缓存容量,为系统可用内存的1/4
- mLruCache=newLruCache<String,Bitmap>(cacheSize){
- @Override
- protectedintsizeOf(Stringkey,Bitmapvalue){
- if(value!=null)
- returnvalue.getRowBytes()*value.getHeight();
- else
- return0;
- }
- @Override
- protectedvoidentryRemoved(booleanevicted,Stringkey,BitmapoldValue,BitmapnewValue){
- if(oldValue!=null)
- //硬引用缓存容量满的时候,会根据LRU算法把最近没有被使用的图片转入此软引用缓存
- mSoftCache.put(key,newSoftReference<Bitmap>(oldValue));
- }
- };
- mSoftCache=newLinkedHashMap<String,SoftReference<Bitmap>>(SOFT_CACHE_SIZE,0.75f,true){
- privatestaticfinallongserialVersionUID=6040103833179403725L;
- @Override
- protectedbooleanremoveEldestEntry(Entry<String,SoftReference<Bitmap>>eldest){
- if(size()>SOFT_CACHE_SIZE){
- returntrue;
- }
- returnfalse;
- }
- };
- }
- /**
- *从缓存中获取图片
- */
- publicBitmapgetBitmapFromCache(Stringurl){
- Bitmapbitmap;
- //先从硬引用缓存中获取
- synchronized(mLruCache){
- bitmap=mLruCache.get(url);
- if(bitmap!=null){
- //如果找到的话,把元素移到LinkedHashMap的最前面,从而保证在LRU算法中是最后被删除
- mLruCache.remove(url);
- mLruCache.put(url,bitmap);
- returnbitmap;
- }
- }
- //如果硬引用缓存中找不到,到软引用缓存中找
- synchronized(mSoftCache){
- SoftReference<Bitmap>bitmapReference=mSoftCache.get(url);
- if(bitmapReference!=null){
- bitmap=bitmapReference.get();
- if(bitmap!=null){
- //将图片移回硬缓存
- mLruCache.put(url,bitmap);
- mSoftCache.remove(url);
- returnbitmap;
- }else{
- mSoftCache.remove(url);
- }
- }
- }
- returnnull;
- }
- /**
- *添加图片到缓存
- */
- publicvoidaddBitmapToCache(Stringurl,Bitmapbitmap){
- if(bitmap!=null){
- synchronized(mLruCache){
- mLruCache.put(url,bitmap);
- }
- }
- }
- publicvoidclearCache(){
- mSoftCache.clear();
- }
- }
- publicclassImageFileCache{
- privatestaticfinalStringCACHDIR="ImgCach";
- privatestaticfinalStringWHOLESALE_CONV=".cach";
- privatestaticfinalintMB=1024*1024;
- privatestaticfinalintCACHE_SIZE=10;
- privatestaticfinalintFREE_SD_SPACE_NEEDED_TO_CACHE=10;
- publicImageFileCache(){
- //清理文件缓存
- removeCache(getDirectory());
- }
- /**从缓存中获取图片**/
- publicBitmapgetImage(finalStringurl){
- finalStringpath=getDirectory()+"/"+convertUrlToFileName(url);
- Filefile=newFile(path);
- if(file.exists()){
- Bitmapbmp=BitmapFactory.decodeFile(path);
- if(bmp==null){
- file.delete();
- }else{
- updateFileTime(path);
- returnbmp;
- }
- }
- returnnull;
- }
- /**将图片存入文件缓存**/
- publicvoidsaveBitmap(Bitmapbm,Stringurl){
- if(bm==null){
- return;
- }
- //判断sdcard上的空间
- if(FREE_SD_SPACE_NEEDED_TO_CACHE>freeSpaceOnSd()){
- //SD空间不足
- return;
- }
- Stringfilename=convertUrlToFileName(url);
- Stringdir=getDirectory();
- FiledirFile=newFile(dir);
- if(!dirFile.exists())
- dirFile.mkdirs();
- Filefile=newFile(dir+"/"+filename);
- try{
- file.createNewFile();
- OutputStreamoutStream=newFileOutputStream(file);
- bm.compress(Bitmap.CompressFormat.JPEG,100,outStream);
- outStream.flush();
- outStream.close();
- }catch(FileNotFoundExceptione){
- Log.w("ImageFileCache","FileNotFoundException");
- }catch(IOExceptione){
- Log.w("ImageFileCache","IOException");
- }
- }
- /**
- *计算存储目录下的文件大小,
- *当文件总大小大于规定的CACHE_SIZE或者sdcard剩余空间小于FREE_SD_SPACE_NEEDED_TO_CACHE的规定
- *那么删除40%最近没有被使用的文件
- */
- privatebooleanremoveCache(StringdirPath){
- Filedir=newFile(dirPath);
- File[]files=dir.listFiles();
- if(files==null){
- returntrue;
- }
- if(!android.os.Environment.getExternalStorageState().equals(
- android.os.Environment.MEDIA_MOUNTED)){
- returnfalse;
- }
- intdirSize=0;
- for(inti=0;i<files.length;i++){
- if(files[i].getName().contains(WHOLESALE_CONV)){
- dirSize+=files[i].length();
- }
- }
- if(dirSize>CACHE_SIZE*MB||FREE_SD_SPACE_NEEDED_TO_CACHE>freeSpaceOnSd()){
- intremoveFactor=(int)((0.4*files.length)+1);
- Arrays.sort(files,newFileLastModifSort());
- for(inti=0;i<removeFactor;i++){
- if(files[i].getName().contains(WHOLESALE_CONV)){
- files[i].delete();
- }
- }
- }
- if(freeSpaceOnSd()<=CACHE_SIZE){
- returnfalse;
- }
- returntrue;
- }
- /**修改文件的最后修改时间**/
- publicvoidupdateFileTime(Stringpath){
- Filefile=newFile(path);
- longnewModifiedTime=System.currentTimeMillis();
- file.setLastModified(newModifiedTime);
- }
- /**计算sdcard上的剩余空间**/
- privateintfreeSpaceOnSd(){
- StatFsstat=newStatFs(Environment.getExternalStorageDirectory().getPath());
- doublesdFreeMB=((double)stat.getAvailableBlocks()*(double)stat.getBlockSize())/MB;
- return(int)sdFreeMB;
- }
- /**将url转成文件名**/
- privateStringconvertUrlToFileName(Stringurl){
- String[]strs=url.split("/");
- returnstrs[strs.length-1]+WHOLESALE_CONV;
- }
- /**获得缓存目录**/
- privateStringgetDirectory(){
- Stringdir=getSDPath()+"/"+CACHDIR;
- returndir;
- }
- /**取SD卡路径**/
- privateStringgetSDPath(){
- FilesdDir=null;
- booleansdCardExist=Environment.getExternalStorageState().equals(
- android.os.Environment.MEDIA_MOUNTED);//判断sd卡是否存在
- if(sdCardExist){
- sdDir=Environment.getExternalStorageDirectory();//获取根目录
- }
- if(sdDir!=null){
- returnsdDir.toString();
- }else{
- return"";
- }
- }
- /**
- *根据文件的最后修改时间进行排序
- */
- privateclassFileLastModifSortimplementsComparator<File>{
- publicintcompare(Filearg0,Filearg1){
- if(arg0.lastModified()>arg1.lastModified()){
- return1;
- }elseif(arg0.lastModified()==arg1.lastModified()){
- return0;
- }else{
- return-1;
- }
- }
- }
- }
网络下载图片
- publicclassImageGetFromHttp{
- privatestaticfinalStringLOG_TAG="ImageGetFromHttp";
- publicstaticBitmapdownloadBitmap(Stringurl){
- finalHttpClientclient=newDefaultHttpClient();
- finalHttpGetgetRequest=newHttpGet(url);
- try{
- HttpResponseresponse=client.execute(getRequest);
- finalintstatusCode=response.getStatusLine().getStatusCode();
- if(statusCode!=HttpStatus.SC_OK){
- Log.w(LOG_TAG,"Error"+statusCode+"whileretrievingbitmapfrom"+url);
- returnnull;
- }
- finalHttpEntityentity=response.getEntity();
- if(entity!=null){
- InputStreaminputStream=null;
- try{
- inputStream=entity.getContent();
- FilterInputStreamfit=newFlushedInputStream(inputStream);
- returnBitmapFactory.decodeStream(fit);
- }finally{
- if(inputStream!=null){
- inputStream.close();
- inputStream=null;
- }
- entity.consumeContent();
- }
- }
- }catch(IOExceptione){
- getRequest.abort();
- Log.w(LOG_TAG,"I/Oerrorwhileretrievingbitmapfrom"+url,e);
- }catch(IllegalStateExceptione){
- getRequest.abort();
- Log.w(LOG_TAG,"IncorrectURL:"+url);
- }catch(Exceptione){
- getRequest.abort();
- Log.w(LOG_TAG,"Errorwhileretrievingbitmapfrom"+url,e);
- }finally{
- client.getConnectionManager().shutdown();
- }
- returnnull;
- }
- /*
- *AnInputStreamthatskipstheexactnumberofbytesprovided,unlessitreachesEOF.
- */
- staticclassFlushedInputStreamextendsFilterInputStream{
- publicFlushedInputStream(InputStreaminputStream){
- super(inputStream);
- }
- @Override
- publiclongskip(longn)throwsIOException{
- longtotalBytesSkipped=0L;
- while(totalBytesSkipped<n){
- longbytesSkipped=in.skip(n-totalBytesSkipped);
- if(bytesSkipped==0L){
- intb=read();
- if(b<0){
- break;//wereachedEOF
- }else{
- bytesSkipped=1;//wereadonebyte
- }
- }
- totalBytesSkipped+=bytesSkipped;
- }
- returntotalBytesSkipped;
- }
- }
- }
权限
[html] view plain copy- <uses-permissionandroid:name="android.permission.INTERNET"/>
- <uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
更多相关文章
- Android(安卓)ApiDemos示例解析(88):Media->VideoView
- Android热修复三部曲之动态加载补丁.dex文件
- android之ION内存管理器(1)-- 简介
- 探索Android该Parcel机制上
- 探索Android该Parcel机制(上)
- Android异步加载图像(含线程池,缓存方法)
- Android学习之Service(下)
- android 内存清理
- Android(安卓)SDK更新后 ADT R17 E/AndroidRuntime : java.lang.