Android 通过软引用实现图片缓存,防止内存溢出

时间:2022-03-23 08:01:54

Java中的SoftReference
即对象的软引用。如果一个对象具有软引用,内存空间足够,垃 圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高 速缓存。使用软引用能防止内存泄露,增强程序的健壮性。   
SoftReference的特点是它的一个实例保存对一个Java对象的软引用, 该软引用的存在不妨碍垃圾收集线程对该Java对象的回收。也就是说,一旦SoftReference保存了对一个Java对象的软引用后,在垃圾线程对 这个Java对象回收前,SoftReference类所提供的get()方法返回Java对象的强引用。另外,一旦垃圾线程回收该Java对象之 后,get()方法将返回null


用Map集合缓存软引用的Bitmap对象

Map<String, SoftReference<Bitmap>> imageCache = new new HashMap<String, SoftReference<Bitmap>>();
//强引用的Bitmap对象
Bitmap bitmap = BitmapFactory.decodeStream(InputStream);
//软引用的Bitmap对象
SoftReference<Bitmap> bitmapcache = new SoftReference<Bitmap>(bitmap);
//添加该对象到Map中使其缓存
imageCache.put("1",softRbitmap);
..
.


//从缓存中取软引用的Bitmap对象
SoftReference<Bitmap> bitmapcache_ = imageCache.get("1");
//取出Bitmap对象,如果由于内存不足Bitmap被回收,将取得空

Bitmap bitmap_ = bitmapcache_.get();

如果程序中需要从网上加载大量的图片 这时就考虑采用在sdcard上建立临时文件夹缓存这些图片了

public class BitmapCache {

    static private BitmapCache cache;

    /** 用于Chche内容的存储 */

    private Hashtable<Integer, MySoftRef> hashRefs;

    /** 垃圾Reference的队列(所引用的对象已经被回收,则将该引用存入队列中) */

    private ReferenceQueue<Bitmap> q;

 

    /**

     * 继承SoftReference,使得每一个实例都具有可识别的标识。

      */

    private class MySoftRef extends SoftReference<Bitmap> {

        private Integer _key = 0;

 

        public MySoftRef(Bitmap bmp, ReferenceQueue<Bitmap> q, int key) {

            super(bmp, q);

            _key = key;

        }

    }

 

    private BitmapCache() {

        hashRefs = new Hashtable<Integer, MySoftRef>();

        q = new ReferenceQueue<Bitmap>();

    }

 

    /**

     * 取得缓存器实例

      */

    public static BitmapCache getInstance() {

        if (cache == null) {

            cache = new BitmapCache();

        }

        return cache;

    }

 

    /**

     * 以软引用的方式对一个Bitmap对象的实例进行引用并保存该引用

      */

    private void addCacheBitmap(Bitmap bmp, Integer key) {

        cleanCache();// 清除垃圾引用

         MySoftRef ref = new MySoftRef(bmp, q, key);

        hashRefs.put(key, ref);

    }

 

    /**

     * 依据所指定的drawable下的图片资源ID号(可以根据自己的需要从网络或本地path下获取),重新获取相应Bitmap对象的实例

     */

    public Bitmap getBitmap(int resId, Context context) {

        Bitmap bmp = null;

        // 缓存中是否有该Bitmap实例的软引用,如果有,从软引用中取得。

         if (hashRefs.containsKey(resId)) {

            MySoftRef ref = (MySoftRef) hashRefs.get(resId);

            bmp = (Bitmap) ref.get();

        }

        // 如果没有软引用,或者从软引用中得到的实例是null,重新构建一个实例,

         // 并保存对这个新建实例的软引用

         if (bmp == null) {

            // 传说decodeStream直接调用JNI>>nativeDecodeAsset()来完成decode,

              // 无需再使用java层的createBitmap,从而节省了java层的空间。

              bmp = BitmapFactory.decodeStream(context.getResources()

                    .openRawResource(resId));

            this.addCacheBitmap(bmp, resId);

        }

        return bmp;

    }

 

    private void cleanCache() {

        MySoftRef ref = null;

        while ((ref = (MySoftRef) q.poll()) != null) {

            hashRefs.remove(ref._key);

        }

    }

 

    /**

     * 清除Cache内的全部内容

     */

    public void clearCache() {

        cleanCache();

        hashRefs.clear();

        System.gc();

        System.runFinalization();

    }

}