热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

详解Android图片的三级缓存及图片压缩

为什么需要图片缓存 Android默认给每个应用只分配16M的内存,所以如果加载过多的图片,为了防止内存溢出,应该将图片缓存起来。图片的三

为什么需要图片缓存

Android默认给每个应用只分配16M的内存,所以如果加载过多的图片,为了防止内存溢出,应该将图片缓存起来。图片的三级缓存分别是:

  • 内存缓存
  • 本地缓存
  • 网络缓存

其中,内存缓存应优先加载,它速度最快;本地缓存次优先加载,它速度也快;网络缓存不应该优先加载,它走网络,速度慢且耗流量。

三级缓存的具体实现

网络缓存

  • 根据图片的url去加载图片
  • 在本地和内存中缓存

  

 public class NetCacheUtils {

    private LocalCacheUtils mLocalCacheUtils;
    private MemoryCacheUtils mMemoryCacheUtils;

    public NetCacheUtils(LocalCacheUtils localCacheUtils,
        MemoryCacheUtils memoryCacheUtils) {
      mLocalCacheUtils = localCacheUtils;
      mMemoryCacheUtils = memoryCacheUtils;
    }

    /**
     * 从网络下载图片
     * 
     * @param ivPic
     * @param url
     */
    public void getBitmapFromNet(ImageView ivPic, String url) {
      new BitmapTask().execute(ivPic, url);// 启动AsyncTask,
                          // 参数会在doInbackground中获取
    }

    /**
     * Handler和线程池的封装
     * 
     * 第一个泛型: 参数类型 第二个泛型: 更新进度的泛型, 第三个泛型是onPostExecute的返回结果
     * 
     * 
     */
    class BitmapTask extends AsyncTask {

      private ImageView ivPic;
      private String url;

      /**
       * 后台耗时方法在此执行, 子线程
       */
      @Override
      protected Bitmap doInBackground(Object... params) {
        ivPic = (ImageView) params[0];
        url = (String) params[1];

        ivPic.setTag(url);// 将url和imageview绑定

        return downloadBitmap(url);
      }

      /**
       * 更新进度, 主线程
       */
      @Override
      protected void onProgressUpdate(Void... values) {
        super.onProgressUpdate(values);
      }

      /**
       * 耗时方法结束后,执行该方法, 主线程
       */
      @Override
      protected void onPostExecute(Bitmap result) {
        if (result != null) {
          String bindUrl = (String) ivPic.getTag();

          if (url.equals(bindUrl)) {// 确保图片设定给了正确的imageview
            ivPic.setImageBitmap(result);
            mLocalCacheUtils.setBitmapToLocal(url, result);// 将图片保存在本地
            mMemoryCacheUtils.setBitmapToMemory(url, result);// 将图片保存在内存
            System.out.println("从网络缓存读取图片啦...");
          }
        }
      }
    }

    /**
     * 下载图片
     * 
     * @param url
     * @return
     */
    private Bitmap downloadBitmap(String url) {

      HttpURLConnection cOnn= null;
      try {
        cOnn= (HttpURLConnection) new URL(url).openConnection();

        conn.setConnectTimeout(5000);
        conn.setReadTimeout(5000);
        conn.setRequestMethod("GET");
        conn.connect();

        int respOnseCode= conn.getResponseCode();
        if (respOnseCode== 200) {
          InputStream inputStream = conn.getInputStream();

          //图片压缩处理
          BitmapFactory.Options option = new BitmapFactory.Options();
          option.inSampleSize = 2;//宽高都压缩为原来的二分之一, 此参数需要根据图片要展示的大小来确定
          option.inPreferredCOnfig= Bitmap.Config.RGB_565;//设置图片格式

          Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, option);
          return bitmap;
        }

      } catch (Exception e) {
        e.printStackTrace();
      } finally {
        conn.disconnect();
      }

      return null;
    }
  }

本地缓存

两个方法:设置本地缓存,获取本地缓存

  public class LocalCacheUtils {

    public static final String CACHE_PATH = Environment
        .getExternalStorageDirectory().getAbsolutePath() + "/local_cache";

    /**
     * 从本地sdcard读图片
     */
    public Bitmap getBitmapFromLocal(String url) {
      try {
        String fileName = MD5Encoder.encode(url);
        File file = new File(CACHE_PATH, fileName);

        if (file.exists()) {
          Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(
              file));
          return bitmap;
        }

      } catch (Exception e) {
        e.printStackTrace();
      }

      return null;
    }

    /**
     * 向sdcard写图片
     * 
     * @param url
     * @param bitmap
     */
    public void setBitmapToLocal(String url, Bitmap bitmap) {
      try {
        String fileName = MD5Encoder.encode(url);

        File file = new File(CACHE_PATH, fileName);

        File parentFile = file.getParentFile();
        if (!parentFile.exists()) {// 如果文件夹不存在, 创建文件夹
          parentFile.mkdirs();
        }

        // 将图片保存在本地
        bitmap.compress(CompressFormat.JPEG, 100,
            new FileOutputStream(file));
      } catch (Exception e) {
        e.printStackTrace();
      }

    }
  }

内存缓存

两个方法:设置内存缓存,获取内存缓存

问题:

如果使用HashMap存储图片时,当图片越来越多时,会导致内存溢出,因为它是强引用,java的垃圾回收器不会回收。

如若改成软引用SoftReference(内存不够时,垃圾回收器会考虑回收),仍有一个问题:在android2.3+, 系统会优先将SoftReference的对象提前回收掉, 即使内存够用。

解决办法:可以用LruCache来解决上述内存不回收或提前回收的问题。least recentlly use 最少最近使用算法 它会将内存控制在一定的大小内, 超出最大值时会自动回收, 这个最大值开发者自己定
 

    public class MemoryCacheUtils {

      // private HashMap> mMemoryCache = new
      // HashMap>();
      private LruCache mMemoryCache;

      public MemoryCacheUtils() {
        long maxMemory = Runtime.getRuntime().maxMemory() / 8;// 模拟器默认是16M
        mMemoryCache = new LruCache((int) maxMemory) {
          @Override
          protected int sizeOf(String key, Bitmap value) {
            int byteCount = value.getRowBytes() * value.getHeight();// 获取图片占用内存大小
            return byteCount;
          }
        };
      }

      /**
       * 从内存读
       * 
       * @param url
       */
      public Bitmap getBitmapFromMemory(String url) {
        // SoftReference softReference = mMemoryCache.get(url);
        // if (softReference != null) {
        // Bitmap bitmap = softReference.get();
        // return bitmap;
        // }
        return mMemoryCache.get(url);
      }

      /**
       * 写内存
       * 
       * @param url
       * @param bitmap
       */
      public void setBitmapToMemory(String url, Bitmap bitmap) {
        // SoftReference softReference = new
        // SoftReference(bitmap);
        // mMemoryCache.put(url, softReference);
        mMemoryCache.put(url, bitmap);
      }
    }

图片压缩

  //图片压缩处理(在从网络获取图片的时候就进行压缩)
  BitmapFactory.Options option = new BitmapFactory.Options();
  option.inSampleSize = 2;//宽高都压缩为原来的二分之一, 此参数需要根据图片要展示的大小来确定
  option.inPreferredCOnfig= Bitmap.Config.RGB_565;//设置图片格式
  Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, option);

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • 本文将详细介绍如何配置并整合MVP架构、Retrofit网络请求库、Dagger2依赖注入框架以及RxAndroid响应式编程库,构建高效、模块化的Android应用。 ... [详细]
  • 本文介绍了如何通过 ADB 命令行工具启动和停止 Android 应用。通过简单的命令,您可以轻松地控制设备上的应用运行状态。 ... [详细]
  • SPFA算法详解与应用
    当图中包含负权边时,传统的最短路径算法如Dijkstra不再适用,而Bellman-Ford算法虽然能解决问题,但其时间复杂度过高。SPFA算法作为一种改进的Bellman-Ford算法,能够在多数情况下提供更高效的解决方案。本文将详细介绍SPFA算法的原理、实现步骤及其应用场景。 ... [详细]
  • 深入理解MongoDB的SCRAM-SHA-1认证流程
    本文详细解析了MongoDB的SCRAM-SHA-1认证机制的具体步骤,旨在帮助读者深入了解这一安全认证方法的工作原理及其在实际应用中的重要性。 ... [详细]
  • Web开发实践:创建连连看小游戏
    本文详细介绍了如何在Web环境中开发一款连连看小游戏,适合初学者和技术爱好者参考。通过本文,您将了解游戏的基本结构、连线算法以及实现方法。 ... [详细]
  • 本文介绍了如何使用jQuery获取浏览器窗口的可视区域高度、文档的整体高度以及宽度等关键尺寸信息,包括边界、填充和边距在内的完整尺寸。 ... [详细]
  • 本文详细介绍了Socket在Linux内核中的实现机制,包括基本的Socket结构、协议操作集以及不同协议下的具体实现。通过这些内容,读者可以更好地理解Socket的工作原理。 ... [详细]
  • 探索CNN的可视化技术
    神经网络的可视化在理论学习与实践应用中扮演着至关重要的角色。本文深入探讨了三种有效的CNN(卷积神经网络)可视化方法,旨在帮助读者更好地理解和优化模型。 ... [详细]
  • 我整理了HMOV四大5G旗舰的参数,可依然没能拯救我的选择困难症
    伊瓢茕茕发自凹非寺量子位报道|公众号QbitAI报道了那么多发布会,依然无法选出要换的第一部5G手机。这不,随着华为P40系列发布,目前国 ... [详细]
  • 最优化算法与matlab应用3:最速下降法
    最优化算法与matlab应用3:最速下降法最速下降法是一种沿着N维目标函数的负梯度方向搜索最小值的方法。(1)算法原理函数的负梯度表示如下:搜索步长可调整ak,通常记为(第k次迭代 ... [详细]
  • Java高级工程师学习路径及面试准备指南
    本文基于一位朋友的PDF面试经验整理,涵盖了Java高级工程师所需掌握的核心知识点,包括数据结构与算法、计算机网络、数据库、操作系统等多个方面,并提供了详细的参考资料和学习建议。 ... [详细]
  • 本文探讨了在 Python 2.7 环境下,如何有效地对大量数据(如几百 KB 的字符串)进行加密和压缩,并确保能够准确无误地解密回原始数据。 ... [详细]
  • ACM经典书籍推荐
    本文介绍了几本在算法和计算机科学领域具有重要影响力的书籍,包括由Donald E. Knuth编著的《计算机程序设计艺术》第一卷,以及潘氏兄弟的数论经典教材等。这些书籍不仅是学习相关领域的宝贵资源,也是专业人士不可或缺的参考书。 ... [详细]
  • Linux内核中的内存反碎片技术解析
    本文深入探讨了Linux内核中实现的内存反碎片技术,包括其历史发展、关键概念如虚拟可移动区域以及具体的内存碎片整理策略。旨在为开发者提供全面的技术理解。 ... [详细]
  • 通过两幅详细的思维导图,全面解析Spring框架中应用的设计模式及其核心编程理念。 ... [详细]
author-avatar
artiga靜嵐_524
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有