您的位置:首页 > 移动开发 > Android开发

利用Java Soft Reference技术实现Android图片管理器

2013-05-17 10:13 573 查看
利用Java Soft Reference技术实现Android图片管理器

转自: http://www.cnblogs.com/Airforce-1/archive/2011/09/15/2178170.html
最近做一个项目,需要用到图片管理器,对所有的图片进行全局存储和读取。

目标比较明确:在不抛出OOM异常的情况下,尽量加速图片的读取速度。众所周知,手机这种资源受限型设备,对内存的使用还是需要精打细算的。

本人接触Java时间不长,3个月多一点,对Java的内存管理机制理解的不透彻,所以刚开始走了一些弯路,最后才找到了Soft Reference这个东西。看来,以后必须要学习一下

Java的内存管理啦(此时不得不怀念C的自由和强大)。

言归正传,还是说说这个图片管理器。项目中图片分2种类型,一种是系统资源图片,本质上是编译成Android R的二进制文件;

另一种是用户自定义的图片,大多数以png、bitmap的格式存储在本地或者服务器端。

所以在管理器中设计了2张HashMap存放这两类图片。本来想把图片设计成Bitmap的,后来发现设计成Drawable更加方便。

下面展示一下代码:由于是公司内部的项目,所以代码不能全部贴出来。要保持最起码的职业道德嘛。


public class ImageManager
{
    private static ImageManager gInstance_;
    private static Resources resourcesMan = R.getResources();
    
    private HashMap<Integer, SystemImageRef> systemImageRefs; ///为什么要保存系统图片cache
    private ReferenceQueue<SystemImage> systemImageRefQueue;
    
    private HashMap<String, CustomImageRef> customImageRefs;
    private ReferenceQueue<CustomImage> customImageRefQueue;
    
    public static final String log_tag = "ImageManager ";
    private ImageManager()
    {
        systemImageRefs = new HashMap<Integer, SystemImageRef>();
        systemImageRefQueue = new ReferenceQueue<SystemImage>();
        customImageRefs = new HashMap<String, CustomImageRef>();
        customImageRefQueue = new ReferenceQueue<CustomImage>();
    }
    public static ImageManager getInstance()
    {
        if (gInstance_ == null)
        {
            gInstance_ = new ImageManager();
        }
        return gInstance_;
    }
     public Drawable getSystemImage(int resourceID)
     {
         /* If it's already cached through soft reference, get it directly */ 
        SystemImage sysImage = null;
        if (systemImageRefs.containsKey(resourceID))
        {
            SystemImageRef ref = systemImageRefs.get(resourceID);
            sysImage = ref.get();
        }
        if (null == sysImage)
        {
            sysImage = new SystemImage(resourceID);
            cacheSystemImage(sysImage);
            Log.i(log_tag, "Retrieve image from R, resourceID = " + resourceID);
        }
        return sysImage.getSystemImage(); 
    }
    private void cleanSystemImageCache() 
    { 
        SystemImageRef ref = null; 
        while ((ref = (SystemImageRef) systemImageRefQueue.poll()) != null) 
        { 
            systemImageRefs.remove(ref.resourceID);   ///可以访问私有类对象的私有数据
        } 
        return; 
    }
    private void cacheSystemImage(SystemImage em) ///创建一个system image的cache
    { 
        cleanSystemImageCache(); 
        SystemImageRef ref = new SystemImageRef(em, systemImageRefQueue);  ///把引用加入到引用队列中. 
        systemImageRefs.put(ref.resourceID, ref); 
        return;
     }
     
     
       
    public Drawable getCustomImage(String imageURL) 
    { 
        if (null == imageURL || 0 == imageURL.length()) 
        { 
            return null; 
        }
        /* If it's already cached through soft reference, get it directly */ 
        CustomImage cusImage = null; 
        if(customImageRefs.containsKey(imageURL)) 
        { 
        	  CustomImageRef ref = customImageRefs.get(imageURL); 
            cusImage = ref.get(); 
        }
        if (null == cusImage) 
        { 
            cusImage = new CustomImage(imageURL); 
            cacheCustomImage(cusImage); 
            Log.i(log_tag, "Retrieve image imageURL = " + imageURL); 
        } 
        return cusImage.getCustomImage(); 
    }
    ////------------------------------------------
    private void cacheCustomImage(CustomImage em)   ////创建
    { 
        cleanCustomImageCache(); 
        CustomImageRef ref = new CustomImageRef(em, customImageRefQueue); ///queue用来辅助管理,主要使用poll来管理
        customImageRefs.put(ref.imageURL, ref); ///res是真正干活的
        return;
     } 
    private void cleanCustomImageCache() 
    { 
        CustomImageRef ref = null; 
        while ((ref = (CustomImageRef) customImageRefQueue.poll()) != null) 
        {
             customImageRefs.remove(ref.imageURL); 
        } 
        return; 
    } 
    public void clearCache() 
    { 
        cleanSystemImageCache(); 
        cleanCustomImageCache(); 
        systemImageRefs.clear(); 
        customImageRefs.clear(); 
        System.gc(); 
        //System.runFinalization(); 
        return; 
    }
 
    private class SystemImage 
    { 
        private int resourceID; 
        private Drawable systemDrawable; 
        public SystemImage(int resourceID) 
        { 
            this.resourceID = resourceID; 
            this.systemDrawable = resourcesMan.getDrawable(resourceID); 
        } 
        public int getResourceID() 
        { 
            return this.resourceID; 
        }
        public Drawable getSystemImage() 
        { 
            return this.systemDrawable; 
        } 
    } 
    private class CustomImage 
    { 
        private String imageURL; 
        private Drawable customDrawable;
 
        public CustomImage(String imageURL) 
        { 
            this.imageURL = new String(imageURL); 
            this.customDrawable = FileUtils.getDrawable(imageURL); 
        }
        public String getImagePath() 
        { 
            return this.imageURL; 
        } 
        public Drawable getCustomImage() 
        { 
            return this.customDrawable; 
        } 
    }
    private class SystemImageRef extends SoftReference<SystemImage> 
    { 
        private int resourceID; 
        public SystemImageRef(SystemImage em, ReferenceQueue<SystemImage> q) 
        {
             super(em, q); 
            resourceID = em.getResourceID(); 
        } 
    } 
    private class CustomImageRef extends SoftReference<CustomImage>
    {
        private String imageURL;
        public CustomImageRef(CustomImage em, ReferenceQueue<CustomImage> q)
        {
            super(em, q);
            imageURL = em.getImagePath();
        }
    }
}
  


目前为止,这段代码工作正常,通过打出的日志,可以看见,VM在某些时候的确释放了一些已经缓存在HashMap中的图片,目的大概就是书上说的避免抛出OOM异常吧。但是内存的实际使用效率如何,所谓的Soft Reference到底如何平衡时间和空间的,没有直接的说明数据。我设计了一种实验方法,评估这段代码的效率,用一个XML脚本不停地随机读取图片资源,看看手机的实际反应情况。很不幸,貌似手机反应有点慢,现在郁闷中。另外对于存储在服务器端的图片资源,目前的代码没有考虑到这一点,或许要开一个子线程去网

络上下载图片,那是后话了,目前还有一些人在狂写服务端的代码呢。

根据使用中出现的问题,我会持续更新这段代码的,以期完美实现最初的目标:既省内存又省时间。

另外,希望某位大侠给我介绍一些Java内存管理机制的知识,或者一起探讨一下也行。

ReferenceQueue() Constructs a new reference-object queue.

Method:

Reference<? extends T> poll() -------Polls this queue to see if a reference object is available.

Reference<? extends T> remove() ---Removes the next reference object in this queue, blocking until one becomes available.

Reference<? extends T> remove(long timeout) Removes the next reference object in this queue, blocking until either one becomes available or the given timeout period expire
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐