天天看点

【android】实现图片的三级缓存。工具类

本文主要分析以下几点

  • 为什么使用三级缓存
  • 什么是三级缓存
  • 三级缓存原理
  • 代码的具体实现:有注释
  • 工具类使用方法
  • github分享地址

1、为什么使用三级缓存

  • 如今的 Android App 经常会需要网络交互,通过网络获取图片是再正常不过的事了
  • 假如每次启动的时候都从网络拉取图片的话,势必会消耗很多流量。在当前的状况下,对于非wifi用户来说,流量还是很贵的,一个很耗流量的应用,其用户数量级肯定要受到影响
  • 特别是,当我们想要重复浏览一些图片时,如果每一次浏览都需要通过网络获取,流量的浪费可想而知
  • 因此提出三级缓存策略,通过网络、本地、内存三级缓存图片,来减少不必要的网络交互,避免浪费流量

2、什么是三级缓存

  • 网络缓存, 不优先加载, 速度慢,浪费流量
  • 本地缓存, 次优先加载, 速度快
  • 内存缓存, 优先加载, 速度最快

3、三级缓存原理

  • 首次加载 Android App 时,肯定要通过网络交互来获取图片,之后我们可以将图片保存至本地SD卡和内存中
  • 之后运行 App 时,优先访问内存中的图片缓存,若内存中没有,则加载本地SD卡中的图片
  • 总之,只在初次访问新内容时,才通过网络获取图片资源

4、代码的具体实现:有注释

  • 图片缓存工具类
/**
 * 图片加载工具类(三级缓存)
 * <p>
 * 注意:
 * 1.首次加载 Android App 时,肯定要通过网络交互来获取图片,之后我们可以将图片保存至本地SD卡和内存中
 * 2.之后运行 App 时,优先访问内存中的图片缓存,若内存中没有,则加载本地SD卡中的图片
 * 3.总之,只在初次访问新内容时,才通过网络获取图片资源
 * Created by zxp on 2016/6/17.
 */
public class ImageLoaderUtils {

    private static volatile ImageLoaderUtils imageLoaderUtils;

    private MenoryCacheUtils menoryCacheUtils;//内存缓存
    private LocalCacheUtils localCacheUtils;//本地缓存
    private NetBitmapUtils netBitmapUtils;//网络加载

    //单例模式
    public static ImageLoaderUtils getInstance() {
        if (null == imageLoaderUtils) {
            synchronized (ImageLoaderUtils.class) {
                if (null == imageLoaderUtils) {
                    imageLoaderUtils = new ImageLoaderUtils();
                }
            }
        }
        return imageLoaderUtils;
    }

    /**
     * 加载图片
     *
     * @param imageView 图片视图
     * @param url       图片地址
     */
    public void setImageViewFromBitmap(ImageView imageView, String url) {
        setImageViewFromBitmap(imageView, url, NetBitmapUtils.BITMAP_INSAMPLESIZE_ONE);
    }

    /**
     * 加载图片
     *
     * @param imageView      图片视图
     * @param url            图片地址
     * @param compressNumber 压缩倍率
     */
    public void setImageViewFromBitmap(ImageView imageView, String url, int compressNumber) {
        if (menoryCacheUtils == null) {
            menoryCacheUtils = new MenoryCacheUtils();
        }
        if (localCacheUtils == null) {
            localCacheUtils = new LocalCacheUtils();
        }
        if (netBitmapUtils == null) {
            netBitmapUtils = new NetBitmapUtils(menoryCacheUtils, localCacheUtils);
        }
        Bitmap bitmap;
        //从内存缓存
        bitmap = menoryCacheUtils.getBitmap(url);
        if (bitmap != null) {
            setImageView(imageView, bitmap);
            return;
        }
        //本地缓存
        bitmap = localCacheUtils.getBitmap(url);
        if (bitmap != null) {
            setImageView(imageView, bitmap);
            menoryCacheUtils.saveBitmap(url, bitmap);
            return;
        }
        //网络获取
        netBitmapUtils.getBitmap(imageView, url, compressNumber);
    }

    //设置图片
    private void setImageView(ImageView imageView, Bitmap bitmap) {
        imageView.setImageBitmap(bitmap);
    }
}
           
  • 内存缓存工具类
/**
 * 内存缓存
 * Created by zxp on 2016/6/17.
 */
public class MenoryCacheUtils {

    private LruCache<String, Bitmap> lruCache;

    public MenoryCacheUtils() {
        //通常得到手机最大内存的1/8,如果app在使用过程中超过这个,会自动回收
        long maxMenory = Runtime.getRuntime().maxMemory() / ;
        lruCache = new LruCache<String, Bitmap>((int) maxMenory) {
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getByteCount();
            }
        };
    }

    /**
     * 写入图片到内存
     *
     * @param url    地址
     * @param bitmap 图片
     */
    public void saveBitmap(String url, Bitmap bitmap) {
        lruCache.put(url, bitmap);
    }

    /**
     * 从内存中拿到图片
     *
     * @param url 地址
     */
    public Bitmap getBitmap(String url) {
        return lruCache.get(url);
    }

}
           
  • 本地缓存工具类
/**
 * 本地缓存工具类
 * Created by zxp on 2016/6/17.
 */
public class LocalCacheUtils {

    //文件村粗的路径
    private static final String CACHE_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() +
            "/ImageCache";

    /**
     * 拿到本地存储的图片
     *
     * @param url 地址
     * @return
     */
    public Bitmap getBitmap(String url) {
        try {
            //截取文件名字
            String fileName = url.substring(url.lastIndexOf("/") + , url.lastIndexOf("."));
            File file = new File(CACHE_PATH, fileName);

            Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(file));
            return bitmap;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 保存图片到本地
     *
     * @param url    地址
     * @param bitmap 图片
     */
    public void saveBitmap(String url, Bitmap bitmap) {
        try {
            String fileName = url.substring(url.lastIndexOf("/") + , url.lastIndexOf("."));
            File file = new File(CACHE_PATH, fileName);

            //判断父目录是否存在,不存在新建一个
            File parentFile = file.getParentFile();
            if (!parentFile.exists()) {
                parentFile.mkdirs();
            }

            //保存图片到本地,
            // 注意第二个参数:如果不压缩是100,表示压缩率为0,如果是30,表示压缩70%;
            bitmap.compress(Bitmap.CompressFormat.JPEG, , new FileOutputStream(file));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
           
  • 网路加载工具类
**
 * 网络加载图片工具类
 * 网络请求拿到的结果数据bitmap,再保存在本地和内存中
 * Created by zxp on //
 */
public class NetBitmapUtils {

    public static final int BITMAP_INSAMPLESIZE_ONE = ;//原图
    public static final int BITMAP_INSAMPLESIZE_HALF = ;//宽高变为1/2
    public static final int BITMAP_INSAMPLESIZE_ONE_THIRD = ;//宽高变为1/3
    public static final int BITMAP_INSAMPLESIZE_ONE_QUARTER = ;//宽高变为1/4

    private LocalCacheUtils localCacheUtils;
    private MenoryCacheUtils menoryCacheUtils;

    //图片压缩倍率(比如:1为不压缩,2为压缩宽高为一半)
    private int compressNumber = ;

    public NetBitmapUtils(MenoryCacheUtils menoryCacheUtils, LocalCacheUtils localCacheUtils) {
        this.menoryCacheUtils = menoryCacheUtils;
        this.localCacheUtils = localCacheUtils;
    }

    public NetBitmapUtils(MenoryCacheUtils menoryCacheUtils, LocalCacheUtils localCacheUtils, int compressNumber) {
        this.menoryCacheUtils = menoryCacheUtils;
        this.localCacheUtils = localCacheUtils;
        this.compressNumber = compressNumber;
    }

    /**
     * 网络下载图片
     *
     * @param iv  显示图片的imagview
     * @param url 网络下载的地址
     */
    public void getBitmap(ImageView iv, String url) {
        getBitmap(iv, url, compressNumber);
    }

    /**
     * 网络下载图片
     *
     * @param iv             显示图片的imagview
     * @param url            网络下载的地址
     * @param compressnumber 图片压缩倍率(1为不压缩)
     */
    public void getBitmap(ImageView iv, String url, int compressnumber) {
        this.compressNumber = compressnumber;
        new ImageViewTask().execute(iv, url, compressnumber);
    }

    /**
     * AsyncTask就是对handler和线程池的封装
     * 第一个泛型:参数类型
     * 第二个泛型:更新进度的泛型
     * 第三个泛型:onPostExecute的返回结果
     */
    class ImageViewTask extends AsyncTask<Object, Void, Bitmap> {

        private ImageView iv;
        private String url;
        private int compressNumber;


        //在后台做耗时操作,运行在子线程
        @Override
        protected Bitmap doInBackground(Object... params) {
            iv = (ImageView) params[];
            url = (String) params[];
            compressNumber = (int) params[];
            return downloadBitmap(url);
        }

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

        //耗时方法(请求网络)结束后执行该方法,在主线程中,带有请求结果的返回值
        @Override
        protected void onPostExecute(Bitmap bitmap) {
            if (bitmap != null) {
                iv.setImageBitmap(bitmap);
                //网络拿到的图片保存到本地
                localCacheUtils.saveBitmap(url, bitmap);
                //网络拿到的图片保存到内存中
                menoryCacheUtils.saveBitmap(url, bitmap);
            }
        }

        private Bitmap downloadBitmap(String url) {

            HttpURLConnection connection = null;
            try {
                connection = (HttpURLConnection) new URL(url).openConnection();
                connection.setConnectTimeout();
                connection.setReadTimeout();
                connection.setRequestMethod("GET");

                //请求成功
                if (connection.getResponseCode() == ) {
                    BitmapFactory.Options options = new BitmapFactory.Options();
                    //图片压缩
                    if (compressNumber > ) {
                        //如果compressNumber为2,宽高压缩为原来的1/2
                        options.inSampleSize = compressNumber;
                    }
                    //ALPHA_8——代表8位Alpha位图
                    //ARGB_4444——代表16位ARGB位图
                    //ARGB_8888——代表32位ARGB位图
                    //RGB_565——代表8位RGB位图
                    options.inPreferredConfig = Bitmap.Config.ARGB_4444;
                    Bitmap bitmap = BitmapFactory.decodeStream(connection.getInputStream(), null, options);
                    return bitmap;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }

    }
}
           

工具类使用方法

ImageLoaderUtils.getInstance().setImageViewFromBitmap(imageView , url);

图片宽高压缩为原来一半:

ImageLoaderUtils.getInstance().setImageViewFromBitmap(imageView , url , 2);

github分享地址

github的Demo