首页 > 系统 > Android > 正文

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

2019-12-12 04:24:04
字体:
来源:转载
供稿:网友

为什么需要图片缓存

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<Object, Void, Bitmap> {      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<String, SoftReference<Bitmap>> mMemoryCache = new      // HashMap<String, SoftReference<Bitmap>>();      private LruCache<String, Bitmap> mMemoryCache;      public MemoryCacheUtils() {        long maxMemory = Runtime.getRuntime().maxMemory() / 8;// 模拟器默认是16M        mMemoryCache = new LruCache<String, Bitmap>((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<Bitmap> 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<Bitmap> softReference = new        // SoftReference<Bitmap>(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);

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

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表