`
flyouting
  • 浏览: 14258 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

关于android中的图片缓冲区问题

阅读更多
    android中的图片缓冲区一直是个问题,包括超出虚拟机所分配的资源上限,重用已回收的bitmap等等,解决这个问题,每个人有每个人不同的方式,这里记录下我在项目中学到的的图片缓冲区的实现方式。

    一个bitmap,可以携带一个属性,标识着这个bitmap最后的使用时间。而我们如果创建一个缓冲区,这个区里的bitmap数量是有一定限制的,否则就会出现内存溢出,超出了虚拟机分给程序的内存空间。而这个bitmap的最后使用时间就是确定删不删除这个bitmap的标志。

   
 /**
     * A Bitmap associated with its last modification date. This can be used to check
     * whether the book covers should be downloaded again.
     */
    public static class ExpiringBitmap {
        public Bitmap bitmap;
        public Calendar lastModified;
    }

   
    通过url去得到bitmap这个方法基本都是一致的,也许有的人写的强壮一点,功能会多一些。下边这个添加了附带cookies。其实多数时候是用不到的。

 /**
     * Loads an image from the specified URL with the specified cookie.
     *
     * @param url The URL of the image to load.
     * @param cookie The cookie to use to load the image.
     *
     * @return The image at the specified URL or null if an error occured.
     */
    public static ExpiringBitmap load(String url, String cookie) {
        ExpiringBitmap expiring = new ExpiringBitmap();

        final HttpGet get = new HttpGet(url);
        if (cookie != null) get.setHeader("cookie", cookie);

        HttpEntity entity = null;
        try {
            final HttpResponse response = HttpManager.execute(get);
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                setLastModified(expiring, response);

                entity = response.getEntity();

                InputStream in = null;
                OutputStream out = null;

                try {
                    in = entity.getContent();
                    if (FLAG_DECODE_BITMAP_WITH_SKIA) {
                        expiring.bitmap = BitmapFactory.decodeStream(in);
                    } else {
                        final ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
                        out = new BufferedOutputStream(dataStream, IOUtilities.IO_BUFFER_SIZE);
                        IOUtilities.copy(in, out);
                        out.flush();

                        final byte[] data = dataStream.toByteArray();
                        expiring.bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
                    }
                } catch (IOException e) {
                    android.util.Log.e(LOG_TAG, "Could not load image from " + url, e);
                } finally {
                    IOUtilities.closeStream(in);
                    IOUtilities.closeStream(out);
                }
            }
        } catch (IOException e) {
            android.util.Log.e(LOG_TAG, "Could not load image from " + url, e);
        } finally {
            if (entity != null) {
                try {
                    entity.consumeContent();
                } catch (IOException e) {
                    android.util.Log.e(LOG_TAG, "Could not load image from " + url, e);
                }
            }
        }

        return expiring;
    }



    在上边的方法里,可以看到有一个setLastModified(expiring, response);这个方法就是给bitmap这个数据添加上最后的修改时间,默认的会赋值成下载完成的时间,当二次访问的时候,我们可以重新赋值新的时间点。
   
   
private static void setLastModified(ExpiringBitmap expiring, HttpResponse response) {
        expiring.lastModified = null;

        final Header header = response.getFirstHeader("Last-Modified");
        if (header == null) return;
        
        if (sLastModifiedFormat == null) {
            sLastModifiedFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z");
        }

        final Calendar calendar = GregorianCalendar.getInstance();
        try {
            calendar.setTime(sLastModifiedFormat.parse(header.getValue()));
            expiring.lastModified = calendar;
        } catch (ParseException e) {
            // Ignore
        }
    }


     从缓冲区中获取bitmap,这个方法基本都是给外部调用的,如果缓冲区存在这个bitmap,会返回,如果不存在就调用load(url)方法去获得这个bitmap数据并且放入缓冲区中。

   
 /**
     * Retrieves a drawable from the book covers cache, identified by the specified id.
     * If the drawable does not exist in the cache, it is loaded and added to the cache.
     * If the drawable cannot be added to the cache, the specified default drwaable is
     * returned.
     *
     * @param id The id of the drawable to retrieve
     * @param defaultCover The default drawable returned if no drawable can be found that
     *         matches the id
     *
     * @return The drawable identified by id or defaultCover
     */
    public static FastBitmapDrawable getCachedCover(String id, FastBitmapDrawable defaultCover) {
        FastBitmapDrawable drawable = null;

        SoftReference<FastBitmapDrawable> reference = sArtCache.get(id);
        if (reference != null) {
            drawable = reference.get();
        }

        if (drawable == null) {
            final Bitmap bitmap = loadCover(id);
            if (bitmap != null) {
                drawable = new FastBitmapDrawable(bitmap);
            } else {
                drawable = NULL_DRAWABLE;
            }

            sArtCache.put(id, new SoftReference<FastBitmapDrawable>(drawable));
        }

        return drawable == NULL_DRAWABLE ? defaultCover : drawable;
    }


    在文件的一开始,我们需要生成一个静态的缓冲区,一般都采用HashMap。

   
private static final HashMap<String, SoftReference<FastBitmapDrawable>> sArtCache =
            new HashMap<String, SoftReference<FastBitmapDrawable>>();


    从缓冲区中删除文件,从一个好的思路上来说,应该是对于缓冲区中所有文件进行一个对比,把那些长时间没有用到的文件删除。这给出的方法比较简单,就是删除所有的缓冲区文件。
   
   
/**
     * Removes all the callbacks from the drawables stored in the memory cache. This
     * method must be called from the onDestroy() method of any activity using the
     * cached drawables. Failure to do so will result in the entire activity being
     * leaked.
     */
    public static void cleanupCache() {
        for (SoftReference<FastBitmapDrawable> reference : sArtCache.values()) {
            final FastBitmapDrawable drawable = reference.get();
            if (drawable != null) drawable.setCallback(null);
        }
    }


    这样一个简单的缓冲区文件基本雏形就有了,其他的需要自己按照自己的需求去写一下方法。或者进行一些有话,比如说这里提出的思路是每次读取一个bitmap时都会重置他的lastModified这个属性,然后在删除时,我们对这个属性进行遍历,删掉低于平均访问水瓶的bitmap,当然这个在以上程序代码中没有明确代码,因为以上代码是为了各自不同需求的基本代码,可以自己进行修改。对于前边这个思路的优化,可以删除掉lastModified这个属性,而采用一个队列的缓冲区方式,每次访问,都把这个bitmap先从队列中取出来,也就是删除,然后添加到队尾,这样的思路好处在于,当缓冲区多大,需要删除掉一些图片时,可以直接删除队首的若干个元素,节约了遍历所有元素的时间。

    其他的对于缓冲区的使用还需要对线程进行一下控制,如果用的不好,也会出现一个线程的空间需求超出了分配给他的大小的异常。一般情况用线程池可以缓解这样的情况。

    这些回头找时间再总结一下吧。
1
1
分享到:
评论

相关推荐

    Android采用双缓冲技术实现画板

    本文实例为大家分享了Android实现画板的具体代码,采用的技术是双缓冲技术,供大家参考,具体...定义一个内存中图片,将他作为缓冲区Bitmap cacheBitmap = null; 2).定义缓冲区Cache的Canvas对象 Canvas cacheCanvas

    Android开发人员不得不收集的代码

    setBufferSize : 设置缓冲区尺寸 文件相关 -&gt; FileUtils.java -&gt; Test getFileByPath : 根据文件路径获取文件 isFileExists : 判断文件是否存在 rename : 重命名文件 isDir : 判断是否是目录 isFile : 判断是否是...

    android开发从入门到项目

    四大组件(服务、广播、ContentProvider、页面容器)基础UI组件(ListView、ViewPager)异步任务机制(AsyncTask、Handler、线程池)布局优化(层级、绘制、碎片化处理)图片加载(Bitmap、缓冲区)3、项目的管理 ...

    Android刮刮卡实现原理与代码讲解

    实现刮刮卡我们可以Get到哪些技能? * 圆形圆角图片的实现原理 * 双缓冲技术绘图 * Bitmap获取像素值数据 * 获取绘制文本的长宽 * 自定义View的掌握 ...2.绘制图层区/前景图片 3.设置xfermode 4.绘制Path

    orch:从Android手机向Emacs Org Mode文件发送涂鸦

    管弦乐队将涂鸦和图片从Android手机发送到Emacs组织模式缓冲区。 当前要求: 运行emacs的计算机和运行orch的电话位于同一网络上。 我正在使用一个简单的中间人服务器,应用程序和emacs都可以与之对话。 emacs 24.3...

    BigPictureRemote:大图远程

    安卓大画面遥控器这是用于 Steam 大图片模式的 Android 控制器。... : SteamKit 项目从 Steam 中提取的协议缓冲区描述符: : 执照 此应用程序不隶属于 Valve、Steam 或其任何合作伙伴。 所有版权保留给其各自所有者。

    docker-protobuf:Jaeger项目的全面协议Docker映像

    协议缓冲区+ Docker 一个轻量级protoc码头工人的形象,发布为jaegertracing/protobuf以,内置的所有依赖,产生多语言代码。 从分叉。 目的 原型文件中的gogoproto批注有助于使内部域模型类型在golang中更有效,但是...

    JAVA上百实例源码以及开源项目

     Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...

    JAVA上百实例源码以及开源项目源代码

    Java数据压缩与传输实例 1个目标文件 摘要:Java源码,文件操作,数据压缩,文件传输 Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、...

    chrome.exe

    Chrome 31.0.1650.63包含15个安全修复,例如同步会话的302定向、v8缓冲区溢出、模态对话框中的地址栏欺诈…… Chrome 31支持Web支付,在用户的授权下,Web开发人员可以通过程序调用浏览器的自动填充数据。这样,在...

Global site tag (gtag.js) - Google Analytics