zoukankan      html  css  js  c++  java
  • 图片缓存策略

    图片缓存策略

    1、图片缓存策略分析

    从网络上加载一张图,然后把它显示到UI上是个很简单的事情。当图片变多时,处理起来就有些麻烦了,很典型的应用场景,如ListView,GridView或者ViePager等。我们既需要保证用户看到更多的图片,以免屏幕出现大面积的空白,又要保证内存能Hold住。

    GC会自动释放一个没有强引用的图片或者View,这本来是个好事情,但为了让用户来回滚动时还能快速加载老图片,通常会使用图片缓存。

    下面分别讨论下,通过使用Memory Cache和Disk Cache来增加UI的响应速度和流畅度。

     

    一、使用Memory Cache

    Memory Cache花费定量的内存来换取对图片的快速访问。可以使用LruCache来快速实现。过去,我们通常使用SoftReference或WeakReference来实现Memory Cache,但是在Android 2.3 (API Level 9)之后,GC对SoftReference和WeakReference回收的更快,所以,SoftReference和WeakReference的效果就很差了。而且,在Android 3.0 (API Level 11)之前,Bitmap的像素数据存放在Native Memory中,如何释放是不确定的,存在着内存泄漏,甚至Crash的风险。

    为了确定LruCache的大小,我们需要参考如下几个因素:

    1、当前进程的剩余内存有多少

    2、为了保证良好的用户体验,应用场景显示多少张图片可以满足要求?

    3、屏幕的density是多少?不同像素的屏幕对图片质量的要求是不一样的,可以据此在取图时做一些优化。

    4、图片被访问的频率是否相差很多?如果是这样的话可以存放在不同的LruCache中。

    5、有时需要在数量和质量之间做一些平衡。比如为图片列表在Memory Cache中缓存

    较多的缩略图,在UI中先显示缩略图,然后在后台加载一张高清的。

    这里没有一个精确的数字来做为指导,需要我们在实际中就以上几个因素进行权衡,设置合适的值。至于如何使用LruCache可以参考Support Library中的Demo。

    二、使用Disk Cache

    Memory Cache可以加快图片的访问速度,但内存有限,不可能所有图片都放在Memory Cache中。当程序先被挤出内存,后又被重新启动时,图片仍需要重新获取。这个时候,可以应用Disk Cache来缓存图片,图片就不需要从网络上获取了,节省了流量,减少了获取时间。但需要注意,Disk Cache的读取涉及到本地IO操作,需要开启后台线程操作。

    我们可以像系统Gallery那样使用ContentProvider。另外,Disk Cache也可以很简单地通过Android源码中提供的DiskLruCache来实现。

    2、图片缓存实现

    一、内存缓存

    //需要导入外部jar文件 android-support-v4.jar

     import android.support.v4.util.LruCache;

     //开辟8M硬缓存空间

    private final int hardCachedSize = 8*1024*1024;  

     

    //hard cache 强引用

    private final LruCache<String, Bitmap> sHardBitmapCache = new LruCache<String, Bitmap>(hardCachedSize)

    {

      @Override

      public int sizeOf(String key, Bitmap value)

      {

             return value.getRowBytes() * value.getHeight();
        }

     

      @Override

      protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue)

      {

        Log.v("tag", "hard cache is full , push to soft cache");
          

        //硬引用缓存区满,将一个最不经常使用的oldvalue推入到软引用缓存区

        sSoftBitmapCahe.put(key, new SoftReference<Bitmap>(oldValue));

       }

    }

     

    //软引用

     private static final int SOFT_CACHE_CAPACITY = 40;

    private final static LinkedHashMap<String, SoftReference<Bitmap>> sSoftBitmapCache = new  LinkedHashMao<String, SoftReference<Bitmap>>(SOFT_CACHE_CAPACITY, 0.75f, true)

    {

      @Override

      public SoftReference<Bitmap> put(String key, SoftReference<Bitmap> value)

      {

        return super.input(key, value);

       }

      @Override

      protected boolean removeEldestEntry(LinkedHashMap.Entry<Stirng, SoftReference<Bitmap>> eldest)

      {

        if(size() > SOFT_CACHE_CAPACITY)

        {

          Log.v("tag", "Soft Reference limit , purge one");

          return true;

        }

      return false;

      }

     }

     

     

     //缓存bitmap

    public boolean putBitmap(String key, Bitmap bitmap)

    {

      if(bitmap != null)

      {

        synchronized(sHardBitmapCache)

        {

          sHardBitmapCache.put(key, bitmap);

        }

        return true;

      }  

      return false;
     }

     

    //从缓存中获取bitmap

    public Bitmap getBitmap(String key)

    {

      synchronized(sHardBitmapCache)

      {

        final Bitmap bitmap = sHardBitmapCache.get(key);

        if(bitmap != null)

        {

          return bitmap;

        }

      }

       //硬引用缓存区间中读取失败,从软引用缓存区间读取

      synchronized(sSoftBitmapCache)

      {

        SoftReference<Bitmap> bitmapReference = sSoftBtimapCache.get(key);
        if(bitmapReference != null)

        {

          final Bitmap bitmap2 = bitmapReference.get();

          if(bitmap2 != null)

          {

            return bitmap2;

          }

          else

          {
                      Log.v("tag", "soft reference 已经被回收");

            sSoftBitmapCache.remove(key);

          }

        }

       }

      return null;

     }

    二、磁盘文件缓存

    private File mCacheDir = context.getCacheDir();

    private static final int MAX_CACHE_SIZE = 20 * 1024 * 1024; //20M

    private final LruCache<String, Long> sFileCache = new LruCache<String, Long>(MAX_CACHE_SIZE)

    {

      @Override
          public int sizeOf(String key, Long value)

      {

        return value.intValue();

      }
      

      @Override

      protected void entryRemoved(boolean evicted, String key, Long oldValue, Long newValue)

      {

        File file = getFile(key);

        if(file != null)

        {

          file.delete();

        }

       }

      private File getFile(String fileName) throws FileNotFoundException

      {

        File file = new File(mCacheDir, fileName);

        if(!file.exists() || !file.isFile())

        {

                 throw new FileNotFoundException("文件不存在或有同名文件夹");

        }

        return file;

       }

      //缓存bitmap到外部存储

      public boolean putBitmap(String key, Bitmap bitmap)

      {

        File file = getFile(key);

        if(file != null)

        {

           Log.v("tag", "文件已经存在");

          return true;

         }

        FileOutputStream fos = getOutputStream(key);

        boolean saved = bitmap.compress(CompressFormat.JPEG, 100, fos);

        fos.flush();

        fos.close();

        if(saved)

        {

          synchronized(sFileCache)

          {

             sFileCache.put(key, getFile(key).length());

           }

          return true; 

        }

        return false;

       }

       //根据key获取OutputStream

      private FileOutputStream getOutputStream(String key)

      {

        if(mCacheDir == null)

        return null;

        FileOutputStream fos = new FileOutputStream(mCacheDir.getAbsolutePath() + File.separator + key);

        return fos;

      }

      //获取bitmap

      private static BitmapFactory.Options sBitmapOptions;

      static

      {

        sBitmapOptions = new BitmapFactory.Options();

        sBitmapOptions.inPurgeable=true; //bitmap can be purged to disk
       }

      public Bitmap getBitmap(String key)

      {

        File bitmapFile = getFile(key);

        if(bitmapFile != null)

        {

          Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(bitmapFile), null, sBitmapOptions);

                if(bitmap != null)

         {

            //重新将其缓存至硬引用中

            ...

          }

             }

      }

    }

     

    摘自:
     

    android读取大图片并缓存 http://www.cnblogs.com/leehongee/p/3323837.html

     
    图片缓存实现策略分析  http://blog.csdn.net/a345017062/article/details/8753649
     
     

    Android 图片缓存处理  http://blog.csdn.net/weiyidemaomao/article/details/21237833

  • 相关阅读:
    easyui的页面等待提示层,即mask
    easyui datebox 只选择年月
    java poi Excel导入 整数浮点数转换问题解决
    js去除日期字符串时分秒
    获得元素上的所有属性
    人月神话阅读笔记(二)
    人月神话读后感(一)
    独立冲刺阶段(四)
    独立冲刺阶段(三)
    独立冲刺阶段(二)
  • 原文地址:https://www.cnblogs.com/shaweng/p/3920693.html
Copyright © 2011-2022 走看看