Bitmap的加载和Cache
2018-03-20 21:59
387 查看
本次主要是包含3个方面的内容,首先讲述如何有效的加载一个bitmap。由于bitmap特殊性以及Android对单个应用所施加的内容限制。这个导致加载bitmap的时候很容易出现内存溢出。 java.lang.OutOfMemoryError:bitmap size exceeds VM budget. 根据上述情况,在android开发中需要经常对bitmap做缓存,通过缓存策略,我们不需要每次都从网络上请求图片或者从内存中加载图片,会极大的提高加载效率以及产品的用户体验。目前常用的缓存策略是LruCache和DiskLruCache。其中LruCache被看做是内存缓存,DiskLruCache被看做是存储缓存。通俗的来说就是:最少使用算法。算法的核心思想: 当缓存快满的时候,会淘汰近期最少使用的缓存目标,很显然Lru算法的思想是很容易被接受的。
Bitmap的高校加载:
这个介绍biemap的高效加载之前,先说一下如何加载一个biemap。BitmapFactory类提供了四类方法:decodeFile、decodeRessource、decodeStream和decodeByteArray,分别是用于支持从文件系统、资源、输入流以及字节数组中加载出一二Bitmap对象。 如何高效的加载一个Bitmap对象:其实核心思想也很简单,那就是采用BitmapFactory.Options来加载所需尺寸的图片。通过inSampleSize()可以获取到采样率来加载缩小后的图片,将缩小后的图片在对应的位置显示,这样会降低内存占用从而在一定程度上避免OOM。提高了加载时的性能。 inSampleSize方法的值为1的时候,表示采样后的图片大小为图片的原始大小,当值为2的时候:
公式: 采样后的图片大小其宽/高均为原图大小的1/2,像素数为原图的1/4
通过采样率就能有效的加载图片,那么到底如何获取采样率: (1)将BitmapFactory.Options的inJustDecodeBounds参数设为true并加载图片。 (2)BitmapFactory.Options中获取图片的原始宽高信息,它们对应于outWidth和outHeight参数。 (3)根据采样率的规则结合目标view的所需大小计算出采样率inSampleSize。 (4)将BitmapFactory.Options的inJustDecodeBounds参数设为false,然后冲洗加载图片。将上面的四个流程用程序来实现,如下:
Android中的缓存策略: 缓存的机制: 当程序第一次从网上加载图片后,就将其缓存到内存设备上,这样下次使用这张图片就不用再从网络上获取了,这样就节省了用户的流量,提高了应用的用户体验。往往还会把图片在内存中再缓存一份,这样当应用打算从网络上请求一张图片的时,程序会先从内存中获取,如果内存设备中也没有,就从存储设备中获取,如果存储设备也没有,那就从网络上获取。 目的: 内存中加载图片比在存储中加载图片要快。既提高了程序的效率又为用户节省了不不必要的流量开销。
缓存策略主要包含缓存的添加、获取和删除三类操作。 添加: 获取: 删除:缓存是有大小的,所以会有删除的操作。
LRU算法: 概念:常用的缓存算法,LRU是近期最少使用算法。核心思想就是当缓存满时,会优先淘汰近期使用最少的缓存对象。LRU算法的缓存有两种:LurCache和DiskLruCache,LurCache用于实现内存缓存,DiskLruCache则充当了存储设备缓存。
LurCache: LurCache是android3.1提供的缓存类,通过support-V4兼容包可以兼容到早期的android版本。 LurCache是一个泛型类,内部采用LinkedHashMap以强引用的方式存储外界的缓存对象。提供了get和put方法来完成缓存的获取和添加操作。public class LruCache<K, V> {private final LinkedHashMap<K, V> map; 初始化: /** * LruCache的创建 * return: 返回的是位图每一行 所占用的空间数*位图的行数 * 最后除以1024得到的是KB。 */ int maxMemory = (int)(Runtime.getRuntime().maxMemory()/1024); //总容量的大小为当前进程的可用内存的1/8,单位是KB。 int cacheSize = maxMemory/8; LruCache<String,Bitmap>linkedHashMap = new LruCache<String,Bitmap>(cacheSize){ @Override protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getRowBytes()*bitmap.getHeight()/1024; } };
获取:linkedHashMap .get(key); 添加:linkedHashMap.put(key,bitmap); 删除:linkedHashMap.remove(key);
DiskLruCache: 概念:DiskLruCache用于实现存储设备缓存,即磁盘缓存,他通过将缓存对象写入文件系统从而实现缓存效果。
创建: public static DiskLruCache open(File directory,int appVersion,iint valueCount,long maxSize) private static final long Disk_cache_size = 1024*1024*50; //50MB File diskCacheDir = getDiskCacheDir(mContent,"bitmap"); if(!diskCacheDir.exists()){ diskCacheDir.mkdirs(); } mDiskLruCache = DiskLruCache.open(diskCacheDir,1,1,DISK_CACHE_SIZE);
添加:
private String hashKeyFormurl(String url) { String cacheKey; try {
MessageDigest mDigest = MessageDigest.getInstance("MD5"); mDigest.update(url.getBytes()); cacheKey = bytesToHexString(mDigest.digest()); } catch (Exception e) { cacheKey = String.valueOf(url.hashCode()); } return cacheKey;
}
private String bytesToHexString(byte[] digest) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < digest.length; i++) { String hex = Integer.toHexString(0xff & digest[i]); if(hex.length() == 1){ sb.append('0'); } sb.append(hex); } return sb.toString(); }
调用: String key = hashKeyFormUrl(url); DiskLruCache.Editor editor = mDiskLruCache .edit(key); if(editor != null ){ OutPutStream ops = editor.newOutPutStream(DISK_CACHE_INDEX); }
当从网络下载图片时,图片流可以通过这个文件输入流写入到文件系统上,实现代码如下: public boolean downloadUrlToStream(String urlString, OutputStream outputStream) { try { URL url = new URL(urlString); urlConnection = (HttpURLConnection) url.openConnection(); in = new BufferedInputStream(urlConnection.getInputStream(), IO_BUFFER_SIZE); out = new BufferedOutputStream(outputStream, IO_BUFFER_SIZE); int b; while ((b = in.read()) != -1) { out.write(b); } return true; } catch (Exception e) { // TODO: handle exception } finally { if (urlConnection != null) { urlConnection.disconnect(); } try { in.close(); out.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return false; }
调用: OutputStream outputStream = Editor.newOutPutStream(DISK_CACHE_INDEX); if(downloadUrlToStream(url,outputStream)){ editor.commit(); }else { editor.abort(); } mDiskLruCache.flush();
上述代码,图片已经被正确的写入到文件系统中了,
缓存查找: 通过DiskLruCache方法的get方法得到一个Snapshot对象,紧接着通过Snapshot得到一个文件输入流,自然就能得到bitmap对象了。为了避免OOM,需要参考前面所说的,对图片进行缩放处理,再予以显示,事例代码如下显示: String key = hashKeyFormurl(url); try { DiskLruCache.Snapshot snapshot = mDiskLruCache.get("key"); if (snapshot != null) { FileInputStream fileInputStream = (FileInputStream) snapshot .getInputStream(DISK_CACHE_INDEX); FileDescriptor fileDescriptor = fileInputStream.getFD(); Object mImageResizer; Bitmap bitmap = mImageResizer .decodeSampleBitmapFromFileDescriptor(fileDescriptor, reqWidth, reqHeight); if (bitmap != null) { addBitmapToMemoryCache(key,bitmap); } } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }
Bitmap的高校加载:
这个介绍biemap的高效加载之前,先说一下如何加载一个biemap。BitmapFactory类提供了四类方法:decodeFile、decodeRessource、decodeStream和decodeByteArray,分别是用于支持从文件系统、资源、输入流以及字节数组中加载出一二Bitmap对象。 如何高效的加载一个Bitmap对象:其实核心思想也很简单,那就是采用BitmapFactory.Options来加载所需尺寸的图片。通过inSampleSize()可以获取到采样率来加载缩小后的图片,将缩小后的图片在对应的位置显示,这样会降低内存占用从而在一定程度上避免OOM。提高了加载时的性能。 inSampleSize方法的值为1的时候,表示采样后的图片大小为图片的原始大小,当值为2的时候:
公式: 采样后的图片大小其宽/高均为原图大小的1/2,像素数为原图的1/4
通过采样率就能有效的加载图片,那么到底如何获取采样率: (1)将BitmapFactory.Options的inJustDecodeBounds参数设为true并加载图片。 (2)BitmapFactory.Options中获取图片的原始宽高信息,它们对应于outWidth和outHeight参数。 (3)根据采样率的规则结合目标view的所需大小计算出采样率inSampleSize。 (4)将BitmapFactory.Options的inJustDecodeBounds参数设为false,然后冲洗加载图片。将上面的四个流程用程序来实现,如下:
Android中的缓存策略: 缓存的机制: 当程序第一次从网上加载图片后,就将其缓存到内存设备上,这样下次使用这张图片就不用再从网络上获取了,这样就节省了用户的流量,提高了应用的用户体验。往往还会把图片在内存中再缓存一份,这样当应用打算从网络上请求一张图片的时,程序会先从内存中获取,如果内存设备中也没有,就从存储设备中获取,如果存储设备也没有,那就从网络上获取。 目的: 内存中加载图片比在存储中加载图片要快。既提高了程序的效率又为用户节省了不不必要的流量开销。
缓存策略主要包含缓存的添加、获取和删除三类操作。 添加: 获取: 删除:缓存是有大小的,所以会有删除的操作。
LRU算法: 概念:常用的缓存算法,LRU是近期最少使用算法。核心思想就是当缓存满时,会优先淘汰近期使用最少的缓存对象。LRU算法的缓存有两种:LurCache和DiskLruCache,LurCache用于实现内存缓存,DiskLruCache则充当了存储设备缓存。
LurCache: LurCache是android3.1提供的缓存类,通过support-V4兼容包可以兼容到早期的android版本。 LurCache是一个泛型类,内部采用LinkedHashMap以强引用的方式存储外界的缓存对象。提供了get和put方法来完成缓存的获取和添加操作。public class LruCache<K, V> {private final LinkedHashMap<K, V> map; 初始化: /** * LruCache的创建 * return: 返回的是位图每一行 所占用的空间数*位图的行数 * 最后除以1024得到的是KB。 */ int maxMemory = (int)(Runtime.getRuntime().maxMemory()/1024); //总容量的大小为当前进程的可用内存的1/8,单位是KB。 int cacheSize = maxMemory/8; LruCache<String,Bitmap>linkedHashMap = new LruCache<String,Bitmap>(cacheSize){ @Override protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getRowBytes()*bitmap.getHeight()/1024; } };
获取:linkedHashMap .get(key); 添加:linkedHashMap.put(key,bitmap); 删除:linkedHashMap.remove(key);
DiskLruCache: 概念:DiskLruCache用于实现存储设备缓存,即磁盘缓存,他通过将缓存对象写入文件系统从而实现缓存效果。
创建: public static DiskLruCache open(File directory,int appVersion,iint valueCount,long maxSize) private static final long Disk_cache_size = 1024*1024*50; //50MB File diskCacheDir = getDiskCacheDir(mContent,"bitmap"); if(!diskCacheDir.exists()){ diskCacheDir.mkdirs(); } mDiskLruCache = DiskLruCache.open(diskCacheDir,1,1,DISK_CACHE_SIZE);
添加:
private String hashKeyFormurl(String url) { String cacheKey; try {
MessageDigest mDigest = MessageDigest.getInstance("MD5"); mDigest.update(url.getBytes()); cacheKey = bytesToHexString(mDigest.digest()); } catch (Exception e) { cacheKey = String.valueOf(url.hashCode()); } return cacheKey;
}
private String bytesToHexString(byte[] digest) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < digest.length; i++) { String hex = Integer.toHexString(0xff & digest[i]); if(hex.length() == 1){ sb.append('0'); } sb.append(hex); } return sb.toString(); }
调用: String key = hashKeyFormUrl(url); DiskLruCache.Editor editor = mDiskLruCache .edit(key); if(editor != null ){ OutPutStream ops = editor.newOutPutStream(DISK_CACHE_INDEX); }
当从网络下载图片时,图片流可以通过这个文件输入流写入到文件系统上,实现代码如下: public boolean downloadUrlToStream(String urlString, OutputStream outputStream) { try { URL url = new URL(urlString); urlConnection = (HttpURLConnection) url.openConnection(); in = new BufferedInputStream(urlConnection.getInputStream(), IO_BUFFER_SIZE); out = new BufferedOutputStream(outputStream, IO_BUFFER_SIZE); int b; while ((b = in.read()) != -1) { out.write(b); } return true; } catch (Exception e) { // TODO: handle exception } finally { if (urlConnection != null) { urlConnection.disconnect(); } try { in.close(); out.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return false; }
调用: OutputStream outputStream = Editor.newOutPutStream(DISK_CACHE_INDEX); if(downloadUrlToStream(url,outputStream)){ editor.commit(); }else { editor.abort(); } mDiskLruCache.flush();
上述代码,图片已经被正确的写入到文件系统中了,
缓存查找: 通过DiskLruCache方法的get方法得到一个Snapshot对象,紧接着通过Snapshot得到一个文件输入流,自然就能得到bitmap对象了。为了避免OOM,需要参考前面所说的,对图片进行缩放处理,再予以显示,事例代码如下显示: String key = hashKeyFormurl(url); try { DiskLruCache.Snapshot snapshot = mDiskLruCache.get("key"); if (snapshot != null) { FileInputStream fileInputStream = (FileInputStream) snapshot .getInputStream(DISK_CACHE_INDEX); FileDescriptor fileDescriptor = fileInputStream.getFD(); Object mImageResizer; Bitmap bitmap = mImageResizer .decodeSampleBitmapFromFileDescriptor(fileDescriptor, reqWidth, reqHeight); if (bitmap != null) { addBitmapToMemoryCache(key,bitmap); } } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }
相关文章推荐
- 【Android学习】Bitmap的加载和Cache
- 第12章 Bitmap的加载和Cache
- Android Bitmap的加载和Cache
- (十六)Bitmap的加载和Cache
- Bitmap的加载和Cache
- Android——Bitmap的加载和Cache
- Bitmap的加载和Cache(存储)
- Bitmap的加载和Cache
- 十二、Bitmap的加载和Cache
- Bitmap的加载和Cache
- 《android开发艺术探索》笔记之Bitmap的加载和Cache
- Android线程池及Bitmap加载和Cache
- Android Bitmap的加载优化与Cache相关介绍
- Android中Bitmap的加载和Cache(三级缓存 :LruCache,DiskLruCache)学习笔记
- 第十二章 、Bitmap的加载和Cache
- 《Android开发艺术探索》笔记——Bitmap的加载和Cache(二)
- android中的bitmap的加载和cache
- 读书笔记(12) Bitmap的加载和Cache
- 12_Bitmap的加载和Cache
- Bitmap的加载和Cache