Android Bitmaps缓存
Android 开发中,bitmap是引起内存泄漏的罪魁祸首,关于bitmap的加载,缓存策略,官方已经给了很详细的方法:
缓存之Memory Cache:
缓存的策略,是利用应用程序的分配的内存拿出适当的一部分利用LruCache算法进行缓存。关于用多少内存来缓存图片,这个要根据不同的图片,机型和 屏幕的分辨率来进行综合考量,比如对于同一个图片,Galaxy Nexus 就比Nexus S需要的内存多。
以LruCache缓存示例代码:
private LruCache<String, Bitmap> mMemoryCache;@Override
protected void onCreate(Bundle savedInstanceState) {...// Get max available VM memory, exceeding this amount will throw an// OutOfMemory exception. Stored in kilobytes as LruCache takes an// int in its constructor.final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);// Use 1/8th of the available memory for this memory cache.final int cacheSize = maxMemory / 8;mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {@Overrideprotected int sizeOf(String key, Bitmap bitmap) {// The cache size will be measured in kilobytes rather than// number of items.return bitmap.getByteCount() / 1024;}};...
}public void addBitmapToMemoryCache(String key, Bitmap bitmap) {if (getBitmapFromMemCache(key) == null) {mMemoryCache.put(key, bitmap);}
}public Bitmap getBitmapFromMemCache(String key) {return mMemoryCache.get(key);
}
当加载图片的时候,如果缓存里面有图片,就直接从缓存加载,否者就在一个background thread执行加载图片的操作:
public void loadBitmap(int resId, ImageView imageView) {final String imageKey = String.valueOf(resId);final Bitmap bitmap = getBitmapFromMemCache(imageKey);if (bitmap != null) {mImageView.setImageBitmap(bitmap);} else {mImageView.setImageResource(R.drawable.image_placeholder);BitmapWorkerTask task = new BitmapWorkerTask(mImageView);task.execute(resId);}
}
class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {...// Decode image in background.@Overrideprotected Bitmap doInBackground(Integer... params) {final Bitmap bitmap = decodeSampledBitmapFromResource(getResources(), params[0], 100, 100));addBitmapToMemoryCache(String.valueOf(params[0]), bitmap);return bitmap;}...
}
缓存之Disk Cache:
对于图片比较小,图片个数比较少的,已经对加载效率比较快的要求,用Memory Cache无疑是最好的选择,但是当对于,图片比较多的场景,比如,Gridview ,ListView加载大量的图片,内存就吃不消了,这时候,就需要用到磁盘等外部存储设备来进行缓存。
实际上,如果对图片切换比较频繁的话,那么 ContentProvider
绝壁是个好的选择,比如 image gallery application.
关于使用Disk Cache的官方示例代码如下:
private DiskLruCache mDiskLruCache;
private final Object mDiskCacheLock = new Object();
private boolean mDiskCacheStarting = true;
private static final int DISK_CACHE_SIZE = 1024 * 1024 * 10; // 10MB
private static final String DISK_CACHE_SUBDIR = "thumbnails";@Override
protected void onCreate(Bundle savedInstanceState) {...// Initialize memory cache...// Initialize disk cache on background threadFile cacheDir = getDiskCacheDir(this, DISK_CACHE_SUBDIR);new InitDiskCacheTask().execute(cacheDir);...
}class InitDiskCacheTask extends AsyncTask<File, Void, Void> {@Overrideprotected Void doInBackground(File... params) {synchronized (mDiskCacheLock) {File cacheDir = params[0];mDiskLruCache = DiskLruCache.open(cacheDir, DISK_CACHE_SIZE);mDiskCacheStarting = false; // Finished initializationmDiskCacheLock.notifyAll(); // Wake any waiting threads}return null;}
}class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {...// Decode image in background.@Overrideprotected Bitmap doInBackground(Integer... params) {final String imageKey = String.valueOf(params[0]);// Check disk cache in background threadBitmap bitmap = getBitmapFromDiskCache(imageKey);if (bitmap == null) { // Not found in disk cache// Process as normalfinal Bitmap bitmap = decodeSampledBitmapFromResource(getResources(), params[0], 100, 100));}// Add final bitmap to cachesaddBitmapToCache(imageKey, bitmap);return bitmap;}...
}public void addBitmapToCache(String key, Bitmap bitmap) {// Add to memory cache as beforeif (getBitmapFromMemCache(key) == null) {mMemoryCache.put(key, bitmap);}// Also add to disk cachesynchronized (mDiskCacheLock) {if (mDiskLruCache != null && mDiskLruCache.get(key) == null) {mDiskLruCache.put(key, bitmap);}}
}public Bitmap getBitmapFromDiskCache(String key) {synchronized (mDiskCacheLock) {// Wait while disk cache is started from background threadwhile (mDiskCacheStarting) {try {mDiskCacheLock.wait();} catch (InterruptedException e) {}}if (mDiskLruCache != null) {return mDiskLruCache.get(key);}}return null;
}// Creates a unique subdirectory of the designated app cache directory. Tries to use external
// but if not mounted, falls back on internal storage.
public static File getDiskCacheDir(Context context, String uniqueName) {// Check if media is mounted or storage is built-in, if so, try and use external cache dir// otherwise use internal cache dirfinal String cachePath =Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ||!isExternalStorageRemovable() ? getExternalCacheDir(context).getPath() :context.getCacheDir().getPath();return new File(cachePath + File.separator + uniqueName);
}
memory Cache 在UI线程中执行,Disk Cache则是在Backound thread 中执行。
当屏幕旋转,或者其他配置改变的时候,比如电话进来,弹出对话框,对Activity进行销毁,重置的时候,需要对之前缓存进行保存;
比如在一个Fragment中保存缓存对象的代码示例:
private LruCache<String, Bitmap> mMemoryCache;@Override
protected void onCreate(Bundle savedInstanceState) {...RetainFragment retainFragment =RetainFragment.findOrCreateRetainFragment(getFragmentManager());mMemoryCache = retainFragment.mRetainedCache;if (mMemoryCache == null) {mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {... // Initialize cache here as usual}retainFragment.mRetainedCache = mMemoryCache;}...
}class RetainFragment extends Fragment {private static final String TAG = "RetainFragment";public LruCache<String, Bitmap> mRetainedCache;public RetainFragment() {}public static RetainFragment findOrCreateRetainFragment(FragmentManager fm) {RetainFragment fragment = (RetainFragment) fm.findFragmentByTag(TAG);if (fragment == null) {fragment = new RetainFragment();fm.beginTransaction().add(fragment, TAG).commit();}return fragment;}@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setRetainInstance(true);}
}
From :http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html#config-changes
Android Bitmaps缓存相关推荐
- Android 图片缓存之内存缓存技术LruCache,软引用
Android 图片缓存之内存缓存技术LruCache,软引用
- Android图片缓存之Lru算法
前言: 上篇我们总结了Bitmap的处理,同时对比了各种处理的效率以及对内存占用大小.我们得知一个应用如果使用大量图片就会导致OOM(out of memory),那该如何处理才能近可能的降低oom发 ...
- Android图片缓存框架Glide
Android图片缓存框架Glide Glide是Google提供的一个组件.它具有获取.解码和展示视频剧照.图片.动画等功能.它提供了灵活的API,帮助开发者将Glide应用在几乎任何网络协议栈中. ...
- 浅谈Android视频缓存库
背景 我们都了解播放器的作用就是把音视频压缩数据转换成原始的音视频数据渲染出来,这样我们就可以看到画面.听到声音了.这里的播放器就存在两个问题,第一个问题是视频源存在云端,我们每次看完视频之后重新观看 ...
- android图片缓存,直接应用项目中的Android图片缓存技术
前不久搞的Android图片缓存,刚开始引入开源的框架,用着还行,但是在开发中遇到问题,就比如universal-image-loader-1.9.5.jar这个框架吧,在加载图片的时候自定义imag ...
- 将android studio产生的.gradle .android .androidStudio缓存从默认C盘移动到D盘
启动AVD时:haxm device is not found 解决办法:下载haxm补丁包安装即可. why? android studio 在编译的时候会下载 builde.gradle 文件下 ...
- android视频缓存框架 [AndroidVideoCache](https://github.com/danikula/AndroidVideoCache) 源码解析与评估
文章目录 android视频缓存框架 [AndroidVideoCache](https://github.com/danikula/AndroidVideoCache) 源码解析与评估 引言 使用方 ...
- android强制缓存写磁盘,优雅的构建 Android 项目之磁盘缓存(DiskLruCache)
Android 的缓存技术 一个优秀的应用首先它的用户体验是优秀的,在 Android 应用中恰当的使用缓存技术不仅可以缓解服务器压力还可以优化用户的使用体验,减少用户流量的使用.在 Android ...
- (两百九十二) Android DNS缓存学习
参考文档 Android DNS缓存时长的探索_cc0410的博客-CSDN博客_android dns缓存时间 https://blog.csdn.net/xiaoyu_750516366/cate ...
最新文章
- android 课程——样式
- 信息系统项目管理师备考之旅1---学习计划和方法制定
- Math,random()返回区间内的随机数
- centos安装 crf 和 kenlm
- Linux ReviewBoard安装与配置
- 1018 锤子剪刀布 (20分)
- 《个人信息保护法》,教我如何做产品!
- java单例模式7种_Java 单例模式的7种写法
- 支持kubernetes原生Spark 与其他应用的结合(mysql,postgresql,oracle,hdfs,hbase)
- Bootstrap第一坑,.net MVC项目中bootstrap引用Roboto字体,fonts.gstatic.com字体下载过慢导致页面巨卡问题
- 生产质量分析报告常用模板汇总,质量人必备!
- 机器语言入门 w3c,编程语言
- 一款阿里的知识管理工具
- 【算法】泽勒的一致性
- 使用基于全志D1-H的LicheeRV的 86 Panel 与 Tina BSP 实现 RGB 与 SPI 双屏显示
- VUE Router Error matched of undefined
- 基于Python的书店销售管理系统
- Centos破解密码
- 手机不小心把计算机隐藏了怎么恢复出厂设置,图标隐藏了怎么弄出来(手机图标隐藏了怎么恢复)...
- IOS漏洞频出!世界上真的存在没有漏洞的手机吗?