实现三级缓存加载图片

学习Android的人可能都会碰到过OOM的问题,特别是加载很多图片的时候很容易就OOM了。网上一搜,这类问题解答有很多,下面本人分享一下,对三级缓存加载图片的理解和一些工具类代码。

一、理解

三级缓存加载图片就是先从内存找图片,没有的话,再去本地存储里找图片,再没有的话,就只能网络上加载。所以我们要做的就是,第一次把图片从网上加载下来,就存进内存和本地,然后以后需要重新加载该图片的时候,就按照内存->本地->网络的顺序来进行加载。

二、代码实现

理解了思想,代码就很容易实现了。以下是本人写的一些工具类(PS: 由于代码比较简单,如有雷同,纯属巧合 * _ *)

/**
 * 内存缓存工具类
 */
public class MemoryCacheUtil {
    //使用LruCache来缓存图片
    private LruCache<String, Bitmap> imageCache;
    private static MemoryCacheUtil memoryCacheUtil;

    private MemoryCacheUtil() {
       long maxMemory = Runtime.getRuntime().maxMemory() / 8;
       imageCache = new LruCache<String, Bitmap>((int) maxMemory) {
            @Override
            protected int sizeOf(String key, Bitmap value) {
                int byteSize = value.getRowBytes() * value.getHeight();
                return byteSize;
            }
        };
    }

    public static MemoryCacheUtil getInstance() {
        if (memoryCacheUtil == null)
            memoryCacheUtil = new MemoryCacheUtil();
        return memoryCacheUtil;
    }
    //根据url获取图片
    public Bitmap getImage(String url) {
        if (url != null) {
            return imageCache.get(url);
        }
        return null;
    }
    //保存图片
    public void storeImage(String url, Bitmap bitmap) {
        imageCache.put(url, bitmap);
    }

}
/**
 * 本地存储工具类
 */
public class LocalCacheUtil {
    private static LocalCacheUtil localCacheUtil;

    public final String CACHE_PATH = Environment
            .getExternalStorageDirectory().getAbsolutePath()
            + File.separator + "MyImgCache";

    private LocalCacheUtil() {
    }

    public static LocalCacheUtil getInstance() {
        if (localCacheUtil == null)
            localCacheUtil = new LocalCacheUtil();
        return localCacheUtil;
    }

    //根据指定地址获取图片
    public Bitmap getImage(String url) {
        if (url != null) {
            File file = new File(CACHE_PATH, url);
            if (file.exists()) {
                return BitmapFactory.decodeFile(file.getAbsolutePath());
            }
        }
        return null;
    }

    //存储图片到本地
    public void storeImage(String url, Bitmap bitmap) {
        File file = new File(CACHE_PATH, url);
        File parentFile = file.getParentFile();
        if (!parentFile.exists()) {
            parentFile.mkdirs();
        }
        try {
            FileOutputStream fos = new FileOutputStream(file);
            //把图片写进本地
//            bitmap.compress(Bitmap.CompressFormat.PNG, 100,
//                    fos);
            //这里对图片进行压缩,把大小控制在60kb以下
            byte[] data = ImageUtil.getImageByteByCompress(bitmap, 60);
            fos.write(data, 0, data.length);
            fos.flush();
            fos.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
//三级缓存工具类
public class ThreeCacheUtil {

    /**
     * 三级缓存加载图片
     *
     * @param iv  目标控件
     * @param url 图片地址
     */
    public static void loadImage(final ImageView iv, final String url) {
        if (iv == null || url == null) return;
        /**
         * 先尝试从内存取图
         */
        if (MemoryCacheUtil.getInstance().getImage(url) != null) {
            iv.setImageBitmap(MemoryCacheUtil
                    .getInstance().getImage(url));
        }
        //内存没有,再尝试从本地存储取图
        else if (LocalCacheUtil.getInstance().getImage(url) != null) {
            iv.setImageBitmap(LocalCacheUtil
                    .getInstance().getImage(url));
//把加载好的图片写进内存,已便下次可以从内存取图
            MemoryCacheUtil.getInstance().storeImage(url,
                    LocalCacheUtil.getInstance().getImage(url));
        }
        //本地都没有,就从网络上加载,这里用了Volley网络框架,对Volley不熟悉的朋友可能看下面代码会有点懵
        else {
            ImageLoader.ImageCache imageCache = new ImageLoader.ImageCache() {
                @Override
                public Bitmap getBitmap(String s) {
                    return MemoryCacheUtil.getInstance().getImage(url);
                }

                @Override
                public void putBitmap(final String s, final Bitmap bitmap) {
                    final int width = iv.getWidth();
                    final int height = iv.getHeight();
      //这个AsyncTask主要是用于压缩图片任务
    new AsyncTask<Void, Void, Bitmap>() {
         @Override
         protected Bitmap doInBackground(Void... params) {
          //这里对图片进行一些压缩处理,使得展示效果更佳
      Bitmap bitmap1 = ImageUtil.getImageByScale(bitmap,
                                    width, height, 100);
                            return bitmap1;
                        }

          @Override
          protected void onPostExecute(Bitmap bitmap) {
          //把加载好的图片存进内存
MemoryCacheUtil.getInstance().storeImage(url, bitmap);
         //把加载好的图片存进本地
LocalCacheUtil.getInstance().storeImage(url, bitmap);
                        }
                    }.execute();
                }
            };
            ImageLoader imageLoader = new ImageLoader(MyApplication
                    .getInstance().getRequestQueue(), imageCache);
            ImageLoader.ImageListener listener = ImageLoader.getImageListener(iv,
                    R.drawable.icon_default, R.drawable.icon_default);
            imageLoader.get(url, listener);
        }
    }
}

在图片加载的地方只要用一句

ThreeCacheUtil .loadImage(iv, url);

以上是本人对三级缓存加载图片的一些理解和应用,欢迎纠错和补充

猜你喜欢

转载自blog.csdn.net/seasonLai/article/details/52256469
今日推荐