【小白 新手向】 图片三级缓存的快乐你真的GET到了吗?看完必入门的文章。

图片三级缓存

  • (零)图片三级缓存的具体实现步骤
  • (一)网络缓存
    • NetCacheUtils网络缓存工具类
  • (二)本地缓存
    • 工具类 MD5Encoder 加密
    • LocalCacheUtels 本地缓存工具类
  • (三)内存缓存
    • MemoryCacheUtils 内存缓存工具类
  • (四)图片三级缓存工具类整合

(零)图片三级缓存的具体实现步骤

 * 三级缓存设计步骤:
 * 从内存中取图片
 *
 * 从本地文件中取图片
 * 向内存中保持一份
 *
 * 请求网络图片,获取图片,显示到控件上(Hanlder,postion):
 * 向内存 存一份
 * 向本地文件中存一份

因此我们的储存的逻辑是从网络请求开始写的,第二步实现本地缓存,第三步最后实现内存缓存。

其中从内存缓存中获取最快,本地缓存次之,网络请求垫底。

(一)网络缓存

因为网络缓存中需要,向内存 存一份,向本地文件中存一份,因此需要把内存和本地缓存的工具类实例传进来。

NetCacheUtils网络缓存工具类

public class NetCacheUtils {

    //请求图片成功
    public static final int SUCESS = 1;
    public static final int FAIL = 2;
    
    //本地缓存工具类
    private final LocalCacheUtels localCacheUtils;

    //内存缓存工具类
    private final MemoryCacheUtils memoryCacheUtils;

    //线程池服务类
    private ExecutorService service;

    public NetCacheUtils( LocalCacheUtels localCacheUtels, MemoryCacheUtils memoryCacheUtils) {
        this.localCacheUtils = localCacheUtels;
        this.memoryCacheUtils = memoryCacheUtils;
    }

    //联网请求得到图片
    public void getBitmapFromNet(String imageUrl, int position) {
        service= Executors.newFixedThreadPool(10);
        service.execute(new MyRunnable(imageUrl,position));
    }

    class MyRunnable implements Runnable{
        private final int position;
        private String imageUrl;

        public MyRunnable(String imageUrl, int position) {
            this.imageUrl = imageUrl;
            this.position = position;
        }

        @Override
        public void run() {
            //子线程
            //请求网络图片
            try {
                HttpURLConnection connection = (HttpURLConnection) new URL(imageUrl).openConnection();
                connection.setRequestMethod("GET");
                connection.setConnectTimeout(4000);
                connection.setReadTimeout(4000);
                connection.connect();//可写 可不写
                int code = connection.getResponseCode();
                if (code == 200){
                    InputStream is = connection.getInputStream();
                    Bitmap bitmap = BitmapFactory.decodeStream(is);

                    //在内存中缓存一份
                    memoryCacheUtils.putBitmap(imageUrl,bitmap);
                    //在本地中缓存一份
                    localCacheUtils.putBitmap(imageUrl,bitmap);
                }

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


        }
    }

}

(二)本地缓存

工具类 MD5Encoder 加密

//该工具类直接复制粘贴 即可使用
public class MD5Encoder {
    public static String encode(String string) throws Exception {
        byte[] hash = MessageDigest.getInstance("MD5").digest(string.getBytes("UTF-8"));
        StringBuilder hex = new StringBuilder(hash.length * 2);
        for (byte b : hash) {
            if ((b & 0xFF) < 0x10) {
                hex.append("0");
            }
            hex.append(Integer.toHexString(b & 0xFF));
        }
        return hex.toString();
    }
}

LocalCacheUtels 本地缓存工具类

class LocalCacheUtels {

    private final MemoryCacheUtils memoryCacheUtils;

	//传入内存缓存工具类实例
    public LocalCacheUtels(MemoryCacheUtils memoryCacheUtils) {
        this.memoryCacheUtils = memoryCacheUtils;
    }

    /**
     * 获取储存图片
     * @param imageUrl
     * @return
     */
    public Bitmap getBitmapFromUrl(String imageUrl) {


        //判断sd卡是否可用
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
            try {
                String fileName = MD5Encoder.encode(imageUrl);

                File file = new File("/data/data/com.coderpig.beijingnews/beijingnews/",fileName);
                if (file.exists()){
                    FileInputStream is = new FileInputStream(file);
                    Bitmap bitmap = BitmapFactory.decodeStream(is);

                    if (bitmap!=null){
                        memoryCacheUtils.putBitmap(imageUrl,bitmap);
                        LogUtil.e("从本地保存到内存中");
                    }
                    return bitmap;
                }

            } catch (Exception e) {
                e.printStackTrace();
                LogUtil.e("图片本地获取失败");
            }

        }

        return null;
    }

    /**
     * 根据Url 保存图片
     * @param imageUrl:url
     * @param bitmap:图片
     */
    public void putBitmap(String imageUrl, Bitmap bitmap) {
        //保存图片在 /mnt/sdcard/beijingnews/http://。。。。。
        ///data/data/com.coderpig.beijingnews/beijingnews
        //判断sd卡是否可用
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
            try {
                String fileName = MD5Encoder.encode(imageUrl);
                //LogUtil.e("图片保存地址是:" + Environment.getExternalStorageDirectory().toString());
                File file = new File("/data/data/com.coderpig.beijingnews/beijingnews/",fileName);
                if (!file.exists()){
                    file.createNewFile();
                }
                //保存图片
                bitmap.compress(Bitmap.CompressFormat.PNG,100,new FileOutputStream(file));
                LogUtil.e("图片本地缓存--成功");
            } catch (Exception e) {
                e.printStackTrace();
                LogUtil.e("图片本地缓存--失败");
            }

        }

    }
}

(三)内存缓存

MemoryCacheUtils 内存缓存工具类

不得不提一下LruCache是面试常客,知道怎么用,却不知道它是怎么干的,这就出大问题,知其然得知其所以然,下面这篇链接的文章 可以带你进行一次源码层的遨游。
LruCache实现原理分析 作者:胖子爱你520

class MemoryCacheUtils {

    private LruCache<String, Bitmap> lruCache;

    public MemoryCacheUtils() {
        //使用系统分配给应用的内存的八分之一
        int maxSize = (int) (Runtime.getRuntime().maxMemory()/8);
        lruCache = new LruCache<String, Bitmap>(maxSize){
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getRowBytes() * value.getHeight();
            }
        };

    }

    /**
     * 根据url去取
     * @param imageUrl
     * @return
     */
    public Bitmap getBitmapFromUrl(String imageUrl) {
        return lruCache.get(imageUrl);
    }


    /**
     * 根据ur保存图片到lrucache集合中
     * @param imageUrl
     * @param bitmap
     */
    public void putBitmap(String imageUrl, Bitmap bitmap) {
        lruCache.put(imageUrl,bitmap);
    }
}

(四)图片三级缓存工具类整合

   private MemoryCacheUtils memoryCacheUtils;

    public BitmapCacheUtils(){
        memoryCacheUtils = new MemoryCacheUtils();
        localCacheUtels = new LocalCacheUtels(memoryCacheUtils);
        netCacheUtils = new NetCacheUtils(localCacheUtels,memoryCacheUtils);
    }

    /**
     * 三级缓存设计步骤:
     * 从内存中取图片
     *
     * 从本地文件中取图片
     * 向内存中保持一份
     *
     * 请求网络图片,获取图片,显示到控件上(Hanlder,postion):
     * 向内存 存一份
     * 向本地文件中存一份
     * @param imageUrl
     * @param position
     * @return
     */
    public Bitmap getBitmap(String imageUrl, int position) {
        //1.从内存中取图片
        if (memoryCacheUtils!=null){
            Bitmap bitmap = memoryCacheUtils.getBitmapFromUrl(imageUrl);
            if (bitmap != null){
                LogUtil.e("内存加载图片==成功"+position);
                return bitmap;
            }
        }

        //2.从本地文件中取图片
        if (localCacheUtels != null){
            Bitmap bitmap = localCacheUtels.getBitmapFromUrl(imageUrl);
            if (bitmap != null){
                LogUtil.e("本地加载图片==成功"+position);
                return bitmap;
            }
        }

        //3.请求网络图片,获取图片
        netCacheUtils.getBitmapFromNet(imageUrl,position);
        return null;
    }
}

你可能感兴趣的:(android)