`

Android图片加载

 
阅读更多
转载请注明出处:[作者CJstar]http://blog.csdn.net/cj_star/article/details/48526867

为什么要使用内存缓存
内存缓存:
内存缓存是指将已经赋值的对象保存在内存中,当再次使用的时候直接去内存读取,不再做重复的创建操作。

内存缓存的优势:
对象的重复使用,不再去创建对象,减少内存消耗,便于内存的集中管理。同时在需要读取数据库或者外存的时候,使用内存缓存将大大减少时间,提供程序的整体性能。

内存缓存的原理
JVM垃圾回收机制

JVM采用的是引用计数的机制,处理数据回收的问题。引用计数:即类被加载到内存以后,会在方法区,堆栈,以及程序计数器的地方分配相应的空间,同时对应产生一个引用计数器,专门计数对象被使用的情况。如果新的地方引用了对象,计数器就+1,引用销毁的时候计数器-1,当计数器为0的时候,对象被标记为可被回收。由于该机制不能处理互相引用的情况,加入了根搜索算法,解决互相引用时计数器始终>=1的情况。
引用的类型
强引用:

只要引用存在,垃圾回收器就不会回收。
如:
A a = new A();
B b = new B();
a.b = b;

这时候b属于a的强引用,只有a被回收后b才能被回收。

软引用:

软引用是非必须的引用,当内存不足时可被回收的 。
如:
Java
A a = new A();
SoftRefernece<A> softA = new SoftRefernece<A>(a);
softA.get();//取A的值

如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。


弱引用:

第二次垃圾回收时回收

Java
A a = new A();
WeakReference<A> weakA = new WeakReference<A>(a);
weakA.get();//获取A对象
weakA.isEnQueued();//返回垃圾回收器是否将其标记为可回收。

软引用第一次垃圾回收器扫描到的时候不会马上回收,会把它标记为可回收资源,第二次JVM回收内存的时候如果a还未被引用过,内存将被回收,这时softA.get()返回值是null。这样的好处是a对象可以短暂被保存,但是每次用get方法取值时都需要判断对象是否为空!

虚引用:

每次JVM回收垃圾的时候都会被回收。
Java
A a = new A();
PhantomReference<A> phantomA = new PhantomReference<A>(a);
phantomA.get();//永远返回null
phantomA.isEnQueued();//返回内存中已删除

虚引用是每次垃圾回收的时候都会被回收,通过虚引用的get方法永远获取到的数据为null,因此也被成为幽灵引用。

内存缓存的实现策略

Java
/**
* 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地址](https://github.com/CJstar/Vinci)
0
1
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics