Android图片加载优化--图片缓存
2015-09-17 19:52
375 查看
转载请注明出处:作者CJstar
内存缓存是指将已经赋值的对象保存在内存中,当再次使用的时候直接去内存读取,不再做重复的创建操作。
内存缓存的优势:
对象的重复使用,不再去创建对象,减少内存消耗,便于内存的集中管理。同时在需要读取数据库或者外存的时候,使用内存缓存将大大减少时间,提供程序的整体性能。
JVM采用的是引用计数的机制,处理数据回收的问题。引用计数:即类被加载到内存以后,会在方法区,堆栈,以及程序计数器的地方分配相应的空间,同时对应产生一个引用计数器,专门计数对象被使用的情况。如果新的地方引用了对象,计数器就+1,引用销毁的时候计数器-1,当计数器为0的时候,对象被标记为可被回收。由于该机制不能处理互相引用的情况,加入了根搜索算法,解决互相引用时计数器始终>=1的情况。
* 引用的类型
* * 强引用:
只要引用存在,垃圾回收器就不会回收。
如:
这时候b属于a的强引用,只有a被回收后b才能被回收。
软引用:
软引用是非必须的引用,当内存不足时可被回收的 。
如:
如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。
弱引用:
第二次垃圾回收时回收
软引用第一次垃圾回收器扫描到的时候不会马上回收,会把它标记为可回收资源,第二次JVM回收内存的时候如果a还未被引用过,内存将被回收,这时softA.get()返回值是null。这样的好处是a对象可以短暂被保存,但是每次用get方法取值时都需要判断对象是否为空!
虚引用:
每次JVM回收垃圾的时候都会被回收。
虚引用是每次垃圾回收的时候都会被回收,通过虚引用的get方法永远获取到的数据为null,因此也被成为幽灵引用。
这个缓存是基于LRU算法的缓存机制,LRU即最久未使用算法,当内存不足时将最久未使用的对象放入软引用区,当内存不足时可以及时释放。
项目的GitHub地址
为什么要使用内存缓存
内存缓存:内存缓存是指将已经赋值的对象保存在内存中,当再次使用的时候直接去内存读取,不再做重复的创建操作。
内存缓存的优势:
对象的重复使用,不再去创建对象,减少内存消耗,便于内存的集中管理。同时在需要读取数据库或者外存的时候,使用内存缓存将大大减少时间,提供程序的整体性能。
内存缓存的原理
JVM垃圾回收机制JVM采用的是引用计数的机制,处理数据回收的问题。引用计数:即类被加载到内存以后,会在方法区,堆栈,以及程序计数器的地方分配相应的空间,同时对应产生一个引用计数器,专门计数对象被使用的情况。如果新的地方引用了对象,计数器就+1,引用销毁的时候计数器-1,当计数器为0的时候,对象被标记为可被回收。由于该机制不能处理互相引用的情况,加入了根搜索算法,解决互相引用时计数器始终>=1的情况。
* 引用的类型
* * 强引用:
只要引用存在,垃圾回收器就不会回收。
如:
A a = new A(); B b = new B(); a.b = b;
这时候b属于a的强引用,只有a被回收后b才能被回收。
软引用:
软引用是非必须的引用,当内存不足时可被回收的 。
如:
A a = new A(); SoftRefernece<A> softA = new SoftRefernece<A>(a); softA.get();//取A的值
如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。
弱引用:
第二次垃圾回收时回收
A a = new A(); WeakReference<A> weakA = new WeakReference<A>(a); weakA.get();//获取A对象 weakA.isEnQueued();//返回垃圾回收器是否将其标记为可回收。
软引用第一次垃圾回收器扫描到的时候不会马上回收,会把它标记为可回收资源,第二次JVM回收内存的时候如果a还未被引用过,内存将被回收,这时softA.get()返回值是null。这样的好处是a对象可以短暂被保存,但是每次用get方法取值时都需要判断对象是否为空!
虚引用:
每次JVM回收垃圾的时候都会被回收。
A a = new A(); PhantomReference<A> phantomA = new PhantomReference<A>(a); phantomA.get();//永远返回null phantomA.isEnQueued();//返回内存中已删除
虚引用是每次垃圾回收的时候都会被回收,通过虚引用的get方法永远获取到的数据为null,因此也被成为幽灵引用。
内存缓存的实现策略
/** * Created by CJstar on 15/9/2. */ public class LRUBitmapMemoryCache implements MemmoryCache<Bitmap> { private static final String TAG = "LRUBitmapMemoryCache"; private MemoryCacheOptions options; //强引用 private LruCache<String, Bitmap> mMemoryCache; //软引用 private LinkedHashMap<String, SoftReference<Bitmap>> mSoftCache; /** * Create a instance by default config */ public LRUBitmapMemoryCache() { options = new MemoryCacheOptions.Builder() .setmMaxCacheCount(DefaultConfig.MemoryCacheDefaultOptions.MAXCACHECOUNT) .setmMaxCacheSize(DefaultConfig.MemoryCacheDefaultOptions.MAXCACHESIZE) .setmUseCache(DefaultConfig.MemoryCacheDefaultOptions.USECACHE) .build(); initializeCache(); } /** * set a options as you set * * @param defaultOptions */ @Override public void setOptions(MemoryCacheOptions defaultOptions) { this.options = defaultOptions; } private void initializeCache() { if (options == null) { throw new VinciException("LRUBitmapMemoryCache#options is null"); } if (options.getmMaxCacheSize() == 0) { throw new VinciException("LRUBitmapMemoryCache#max cache size is o"); } if (options.getmMaxCacheCount() == 0) { throw new VinciException("LRUBitmapMemoryCache#max cache count is o"); } MLog.d(TAG, "maxSize:" + options.getmMaxCacheSize() + " maxCount:" + options.getmMaxCacheCount()); mMemoryCache = new LruCache<String, Bitmap>(options.getmMaxCacheSize()) { @Override protected int sizeOf(String key, Bitmap bitmap) { // The cache size will be measured in kilobytes rather than // number of items. return bitmap.getRowBytes() * bitmap.getHeight() / 1024; } @Override protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) { // TODO Auto-generated method stub super.entryRemoved(evicted, key, oldValue, newValue); if (oldValue != null) { // the allocation is full, move bitmap to soft reference mSoftCache.put(key, new SoftReference<Bitmap>(oldValue)); testLog("entryRemoved to mSoftCache:" + key); } } }; mSoftCache = new LinkedHashMap<String, SoftReference<Bitmap>>( options.getmMaxCacheCount(), 0.75f, true) { private static final long serialVersionUID = 6040103833179403725L; @Override protected boolean removeEldestEntry( Entry<String, SoftReference<Bitmap>> eldest) { if (size() > options.getmMaxCacheCount()) { testLog("removeEldestEntry true"); return true; } testLog("removeEldestEntry full"); return false; } }; } @Override public Bitmap get(String key) { testLog("get:" + key); if (TextUtils.isEmpty(key)) { return null; } Bitmap bitmap; // get bitmap from mMemoryCache synchronized (mMemoryCache) { bitmap = mMemoryCache.get(key); if (bitmap != null && !bitmap.isRecycled()) { // LRU : refresh this bitmap position mMemoryCache.remove(key); mMemoryCache.put(key, bitmap); testLog("get mMemoryCache"); return bitmap; } } // get bitmap from mSoftCache synchronized (mSoftCache) { SoftReference<Bitmap> bitmapReference = mSoftCache.get(key); if (bitmapReference != null) { bitmap = bitmapReference.get(); if (bitmap != null && !bitmap.isRecycled()) { // move bitmap to mSoftCache mMemoryCache.put(key, bitmap); mSoftCache.remove(key); testLog("get mSoftCache"); return bitmap; } else { // is recycled mSoftCache.remove(key); } } } return null; } @Override public boolean isExist(String key) { if (TextUtils.isEmpty(key)) { return false; } Bitmap bitmap; // get bitmap from mMemoryCache synchronized (mMemoryCache) { bitmap = mMemoryCache.get(key); if (bitmap != null && !bitmap.isRecycled()) { return true; } } // get bitmap from mSoftCache synchronized (mSoftCache) { SoftReference<Bitmap> bitmapReference = mSoftCache.get(key); if (bitmapReference != null) { bitmap = bitmapReference.get(); if (bitmap != null && !bitmap.isRecycled()) { return true; } } } return false; } @Override public Bitmap remove(String key) { // remove bitmap from mMemoryCache Bitmap bitmap; synchronized (mMemoryCache) { bitmap = mMemoryCache.remove(key); } // remove bitmap from mSoftCache synchronized (mSoftCache) { if (bitmap != null && !bitmap.isRecycled()) { mSoftCache.remove(key); } else { SoftReference<Bitmap> bitmapReference = mSoftCache.remove(key); if (bitmapReference != null) { bitmap = bitmapReference.get(); } } } return bitmap; } @Override public void put(String key, Bitmap bitmap) { if (bitmap == null || bitmap.isRecycled()) { return; } testLog("put:" + key); // thread synchronize synchronized (mMemoryCache) { mMemoryCache.put(key, bitmap); } } @Override public void clear() { synchronized (mMemoryCache) { mMemoryCache.evictAll(); } synchronized (mSoftCache) { mSoftCache.clear(); } } private final boolean ISDEBUG = false; private void testLog(String str) { if (ISDEBUG) { MLog.e(TAG, str); } } }
这个缓存是基于LRU算法的缓存机制,LRU即最久未使用算法,当内存不足时将最久未使用的对象放入软引用区,当内存不足时可以及时释放。
项目的GitHub地址
相关文章推荐
- Android 笔记8
- Android下使用全局变量
- Android5.0源码开发之launcher切换语言后Folder和ShortcutT没有切换到当前语言
- Android开发环境的演变
- android自定义View创建一个Path绘制多边形,贝塞尔曲线,
- Activity显示关闭动画
- android异步加载AsyncTask
- Caused by: android.view.InflateException: Binary XML file line #11: Error inflating class android-su
- Android设备唯一性判断
- Android文字自动横向滚动的TextView(文字长度不够也可以)
- Android推荐书目文章(实时更新....)
- 【转】android fragment 博客 学习
- android 开发环境
- Android0917<二十一>(自定义的View、绘制简单图形、Bitmap)(二)
- Arcgis For Android实现比例尺
- Android-ListActivity单击事件的响应
- Android 自定义View——Path的使用
- iOS中objecive-c语言和android中java语言的区别
- Android自由选择TextView的文字
- 深入理解Android的startservice和bindservice