图片三级缓存策略

2018-03-21  本文已影响7人  HWilliamgo

我们在现实一个图片的时候,按照顺序来是从内存中查找是否有图片缓存,有,直接读取,无,就查找本地文件,有,直接读取,无,通过网络获取。
按照这个步骤一个一个来建立相应的类:

内存缓存

public class MemoryCacheUtils {
//    //强引用
//    private HashMap<String,Bitmap> memoryCache=new HashMap<>();
//    //软引用
//    private HashMap<String,SoftReference<Bitmap>> softMemoryCache=new HashMap<>();
    private LruCache<String,Bitmap> memoryCache;

    public MemoryCacheUtils() {
        //构造函数来实例化一个LruCache
        long maxMemory=Runtime.getRuntime().maxMemory()/8;
        this.memoryCache = new LruCache<String,Bitmap>((int)maxMemory){
            @Override
            protected int sizeOf(String key, Bitmap value) {
                int byteCount= value.getByteCount();
                return byteCount;
            }
        };
    }

    /**
     * 从内存读取bitmap缓存
     * @param url
     * @return
     */
    public Bitmap getBitmapFromMemory(String url){
        Bitmap bitmap=memoryCache.get(url);
        return bitmap;
    }

    /**
     * 设置Bitmap缓存到内存
     * @param url
     * @param bitmap
     */
    public void setBitmapToMemory(String url,Bitmap bitmap){
        memoryCache.put(url,bitmap);
    }
}

本地缓存

public class LocalCacheUtils {
    /**
     * 从本地文件中通过文件名读取缓存图片文件
     * @param url
     * @return
     */
    public Bitmap getBitmapFromLocal(String url) {
        String fileName;
        Bitmap bitmap=null;
        try {
            fileName=Md5.getMD5(url);
            File file=new File(Environment.getExternalStorageDirectory()+"/ImageZip/"+fileName);
            bitmap= BitmapFactory.decodeFile(file.getPath());
        } catch (Exception e) {
            Log.d("info","getBitmapFromLocal wrong");
            e.printStackTrace();
        }
        return bitmap;
    }

    /**
     * 保存缓存图片到本地
     * @param url
     * @param bitmap
     */
    public void setBitmapToLocal(String url, Bitmap bitmap) {
        try {
            String fileName=Md5.getMD5(url);
            File file=new File(Environment.getExternalStorageDirectory()+"/ImageZip/"+fileName);
            if (!file.getParentFile().exists()){
                boolean mkdirs=file.getParentFile().mkdirs();
                Log.d("info","mkdirs:"+mkdirs);
            }
            bitmap.compress(Bitmap.CompressFormat.JPEG,100,new FileOutputStream(file));
        }catch (Exception e){
            Log.d("info","setBitmapToLocal wrong");
            e.printStackTrace();
        }

    }
}

网络缓存
在这里网络请求图片用的是AsynTask。

public class NetCacheUtils {
    //内存缓存工具类
    private MemoryCacheUtils memoryCacheUtils;
    //本地缓存工具类
    private LocalCacheUtils localCacheUtils;

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

    public void getImageFromNet(ImageView imageView, String url){
        new BitmapTask().execute(imageView,url);
    }

    class BitmapTask extends AsyncTask<Object,Integer,Bitmap>{
        private ImageView imageView;
        private String url;
        @Override
        protected Bitmap doInBackground(Object[] objects) {
            imageView=(ImageView) objects[0];
            url=(String) objects[1];
            return downLoadBitmap(url);
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);
            //设置给imageView
            imageView.setImageBitmap(bitmap);
            //保存到本地缓存
            localCacheUtils.setBitmapToLocal(url,bitmap);
            //保存到内存缓存
            memoryCacheUtils.setBitmapToMemory(url,bitmap);
        }
    }
    private Bitmap downLoadBitmap(String url){
        try {
            URL urL = new URL(url);
            HttpURLConnection httpURLConnection = (HttpURLConnection) urL.openConnection();
            httpURLConnection.setRequestMethod("GET");
            httpURLConnection.setReadTimeout(10000);
            if (httpURLConnection.getResponseCode() == 200) {
                InputStream inputStream = httpURLConnection.getInputStream();
                BitmapFactory.Options options=new BitmapFactory.Options();
                options.inSampleSize=2;
                options.inPreferredConfig=Bitmap.Config.ARGB_4444;
                Bitmap bitmap=BitmapFactory.decodeStream(inputStream,null,options);
                inputStream.close();
                return bitmap;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

最后将这三个缓存工具类集成一下:

public class ImageCacheUtils {
    private MemoryCacheUtils memoryCacheUtils;
    private LocalCacheUtils localCacheUtils;
    private NetCacheUtils netCacheUtils;

    public ImageCacheUtils(MemoryCacheUtils memoryCacheUtils, LocalCacheUtils localCacheUtils, NetCacheUtils netCacheUtils) {
        this.memoryCacheUtils = memoryCacheUtils;
        this.localCacheUtils = localCacheUtils;
        this.netCacheUtils = netCacheUtils;
    }
    public void display(ImageView imageView,String url){
        //设置占位符
        imageView.setImageResource(R.mipmap.ic_launcher);
        Bitmap bitmap;
        //从内存缓存中找
        bitmap=memoryCacheUtils.getBitmapFromMemory(url);
        if (bitmap!=null){
            imageView.setImageBitmap(bitmap);
            Log.d("info","从内存缓存加载图片");
            return;
        }
        //内存缓存没有,从本地缓存找
        bitmap=localCacheUtils.getBitmapFromLocal(url);
        if (bitmap!=null){
            imageView.setImageBitmap(bitmap);
            Log.d("info","从本地缓存加载图片");
            //将本地获取的缓存图片保存到内存中
            memoryCacheUtils.setBitmapToMemory(url,bitmap);
            return;
        }
        //本地缓存没有,最后从网络缓存找
        Log.d("info","从网络加载图片");
        netCacheUtils.getImageFromNet(imageView,url);

    }
}

使用:

iv_img = findViewById(R.id.iv_img);
ImageCacheUtils imageCacheUtils=new ImageCacheUtils(memoryCacheUtils,localCacheUtils,netCacheUtils);
imageCacheUtils.display(iv_img,"https://www.baidu.com/img/superlogo_c4d7df0a003d3db9b65e9ef0fe6da1ec.png");

当第一次加载图片的时候,就会用网络去请求,后面就会通过内存或者本地sd卡去加载网络图片了。
当然上面几个类可以通过内部类和单例模式来达到更好的代码结构,为了简单不搞那些了。


以上,图片的三级缓存策略
源码地址:github

上一篇下一篇

猜你喜欢

热点阅读