图片加载避免OOM+代码示例
来源:互联网 发布:网络编辑的工资 编辑:程序博客网 时间:2024/06/04 01:36
总结学习笔记!
一、Android四大图片缓存框架
Android四大图片缓存(Imageloader,Picasso,Glide,Fresco)原理、特性对比
二、OOM问题剖析和解决方案
Android应用中OOM问题剖析和解决方案
三、避免OOM加载图片代码示例
1、ImageLoader
三级的缓存结构:内存绑定url和bitmap,内存绑定url和imageview,内存绑定url和file
先再内存中取,得不到了去读取缓存文件,仍然得不到去请求网络下载,下载到缓存中,然后绑定到内存中
DisplayImage(url,ImageView );调用入口
public class ImageLoader { MemoryCache memoryCache=new MemoryCache(); FileCache fileCache; private Map<ImageView, String> imageViews=Collections.synchronizedMap(new WeakHashMap<ImageView, String>()); ExecutorService executorService; Handler handler=new Handler();//handler to display images in UI thread public ImageLoader(Context context){ fileCache=new FileCache(context); executorService=Executors.newFixedThreadPool(5); } final int stub_id=R.drawable.stub; public void DisplayImage(String url, ImageView imageView) { //每个条目对应一个url imageViews.put(imageView, url); //先从内存中拿到url对应的bitmap Bitmap bitmap=memoryCache.get(url); if(bitmap!=null) //内存拿到立即渲染 imageView.setImageBitmap(bitmap); else { //去走缓存和网络 queuePhoto(url, imageView); imageView.setImageResource(stub_id); } } private void queuePhoto(String url, ImageView imageView) { //主要是为了防止错位 PhotoToLoad p=new PhotoToLoad(url, imageView); //线程池执行加载 executorService.submit(new PhotosLoader(p)); } private Bitmap getBitmap(String url) { File f=fileCache.getFile(url); //from SD cache Bitmap b = decodeFile(f); if(b!=null) return b; //from web try { Bitmap bitmap=null; URL imageUrl = new URL(url); HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection(); conn.setConnectTimeout(30000); conn.setReadTimeout(30000); conn.setInstanceFollowRedirects(true); InputStream is=conn.getInputStream(); OutputStream os = new FileOutputStream(f); Utils.CopyStream(is, os); os.close(); conn.disconnect(); bitmap = decodeFile(f); return bitmap; } catch (Throwable ex){ ex.printStackTrace(); if(ex instanceof OutOfMemoryError) memoryCache.clear(); return null; } } //decodes image and scales it to reduce memory consumption //控制加载进入的大小,进行图片压缩,防止单张图片过大造成oom并且节省内存,还能拿到需要的大小的图片 private Bitmap decodeFile(File f){ try { //decode image size BitmapFactory.Options o = new BitmapFactory.Options(); o.inJustDecodeBounds = true; FileInputStream stream1=new FileInputStream(f); BitmapFactory.decodeStream(stream1,null,o); stream1.close(); //Find the correct scale value. It should be the power of 2. final int REQUIRED_SIZE=70; int width_tmp=o.outWidth, height_tmp=o.outHeight; int scale=1; while(true){ if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE) break; width_tmp/=2; height_tmp/=2; scale*=2; } //decode with inSampleSize BitmapFactory.Options o2 = new BitmapFactory.Options(); o2.inSampleSize=scale; FileInputStream stream2=new FileInputStream(f); Bitmap bitmap=BitmapFactory.decodeStream(stream2, null, o2); stream2.close(); return bitmap; } catch (FileNotFoundException e) { } catch (IOException e) { e.printStackTrace(); } return null; } //Task for the queue private class PhotoToLoad { public String url; public ImageView imageView; public PhotoToLoad(String u, ImageView i){ url=u; imageView=i; } } class PhotosLoader implements Runnable { PhotoToLoad photoToLoad; PhotosLoader(PhotoToLoad photoToLoad){ this.photoToLoad=photoToLoad; } @Override public void run() { try{ if(imageViewReused(photoToLoad)) return; //网络下载到本地缓存 Bitmap bmp=getBitmap(photoToLoad.url); /绑定到内存 memoryCache.put(photoToLoad.url, bmp); if(imageViewReused(photoToLoad)) return; BitmapDisplayer bd=new BitmapDisplayer(bmp, photoToLoad); handler.post(bd); }catch(Throwable th){ th.printStackTrace(); } } } boolean imageViewReused(PhotoToLoad photoToLoad){ String tag=imageViews.get(photoToLoad.imageView); if(tag==null || !tag.equals(photoToLoad.url)) return true; return false; } //Used to display bitmap in the UI thread class BitmapDisplayer implements Runnable { Bitmap bitmap; PhotoToLoad photoToLoad; public BitmapDisplayer(Bitmap b, PhotoToLoad p){bitmap=b;photoToLoad=p;} public void run() { if(imageViewReused(photoToLoad)) return; if(bitmap!=null) photoToLoad.imageView.setImageBitmap(bitmap); else photoToLoad.imageView.setImageResource(stub_id); } } public void clearCache() { memoryCache.clear(); fileCache.clear(); }}
2、MemoryCache
LinkedHashMap有lru的特性。
MemoryCache设置了内存限制,为当前应用运行内存的25%。
关注MemoryCache get() put()方法
public class MemoryCache { private static final String TAG = "MemoryCache"; private Map<String, Bitmap> cache=Collections.synchronizedMap( new LinkedHashMap<String, Bitmap>(10,1.5f,true));//Last argument true for LRU ordering private long size=0;//current allocated size private long limit=1000000;//max memory in bytes public MemoryCache(){ //use 25% of available heap size setLimit(Runtime.getRuntime().maxMemory()/4); } public void setLimit(long new_limit){ limit=new_limit; Log.i(TAG, "MemoryCache will use up to "+limit/1024./1024.+"MB"); } public Bitmap get(String id){ try{ if(!cache.containsKey(id)) return null; //NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78 return cache.get(id); }catch(NullPointerException ex){ ex.printStackTrace(); return null; } } public void put(String id, Bitmap bitmap){ try{ if(cache.containsKey(id)) size-=getSizeInBytes(cache.get(id)); cache.put(id, bitmap); size+=getSizeInBytes(bitmap); //检查加载进来新的bitmap后内存情况,准备清理内存 checkSize(); }catch(Throwable th){ th.printStackTrace(); } } private void checkSize() { Log.i(TAG, "cache size="+size+" length="+cache.size()); if(size>limit){//加载进来后大于限制,就开始清理内存 Iterator<Entry<String, Bitmap>> iter=cache.entrySet().iterator();//least recently accessed item will be the first one iterated while(iter.hasNext()){ Entry<String, Bitmap> entry=iter.next(); size-=getSizeInBytes(entry.getValue()); iter.remove(); if(size<=limit)//直到达到限制内 break; } Log.i(TAG, "Clean cache. New size "+cache.size()); } } public void clear() { try{ //NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78 cache.clear(); size=0; }catch(NullPointerException ex){ ex.printStackTrace(); } } long getSizeInBytes(Bitmap bitmap) { if(bitmap==null) return 0; return bitmap.getRowBytes() * bitmap.getHeight(); }}
3.FileCache
public class FileCache { private File cacheDir; public FileCache(Context context){ //Find the dir to save cached images if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) cacheDir=new File(android.os.Environment.getExternalStorageDirectory(),"LazyList"); else cacheDir=context.getCacheDir(); if(!cacheDir.exists()) cacheDir.mkdirs(); } public File getFile(String url){ //I identify images by hashcode. Not a perfect solution, good for the demo. String filename=String.valueOf(url.hashCode()); //Another possible solution (thanks to grantland) //String filename = URLEncoder.encode(url); File f = new File(cacheDir, filename); return f; } public void clear(){ File[] files=cacheDir.listFiles(); if(files==null) return; for(File f:files) f.delete(); }}
四、图片的压缩式必须的
因为图片的大小=长 X 宽 X 每个像素点占用的字节大小
所以压缩图片就从以上几个方面入手
[bitmap的六种压缩方式,Android图片压缩]
(http://blog.csdn.net/harryweasley/article/details/51955467)
最详细的Android图片压缩解释
阅读全文
0 0
- 图片加载避免OOM+代码示例
- 图片加载,避免OOM
- 如何避免图片加载OOM
- 高效加载图片,避免OOM
- Android避免加载图片出现OOM
- Android加载图片,避免OOM的解决方案
- 【Android应用】加载图片避免oom
- 图片加载,避免oom篇(1)
- Android 大量图片加载,使用什么加载库,避免OOM
- android 加载图片轻松避免OOM(out of memory)
- android 加载图片轻松避免OOM(out of memory)
- android 加载图片轻松避免OOM(out of memory)
- Android高效加载图片,有效避免程序OOM
- 图片处理,如何避免大图片加载的OOM
- Android高效加载图片,有效避免程序OOM
- Android高效加载图片,有效避免程序OOM
- Android高效加载图片,有效避免程序OOM
- 图片压缩和缓存高效加载避免oom
- 解决:MacOS下配置Hadoop及Hive单机遇到的问题(们)
- Windows7下caffe+GPU的详细配置及编译
- Property follows Cocoa naming convention for returning 'owned' objects
- 遍历文件夹和遍历文件
- MSQL之CONCAT函数简单使用
- 图片加载避免OOM+代码示例
- 六月英语总结
- Unity扩展Editor菜单:提供一个统一的接口,来让策划调节prefab里相关脚本的数值
- 编译android用的ijkplayer
- JAVA深入研究——Method的Invoke方法。
- AndroidUI系列
- Android :判断网络是否连接,并设置连接网络
- iOS网络字节序列转换
- springboot配置文件大全