Android开发图片三级缓存

因为目前工程无法使用第三方,只能搞一个三级缓存了三级缓存分为内存缓存,本地缓存,网络缓存;缓存的步骤依次是网络,内存,本地,然后取的顺序为内存,本地,网络.在加载图片时引用时尽量采用弱引用避免出现图片过多产生OOM.

1,内存缓存,android为我们提供LruCache=其中维护着一个LinkedHashMap。LruCache可以用来存储各种类型的数据,我们设置它的大小,一般是系统最大存储空间的1/8.

public class MemoryCacheUtil {

    private LruCache<String, Bitmap> lruCache;

    public MemoryCacheUtil(){
        int maxSize = (int) (Runtime.getRuntime().maxMemory()/8);// 一般获取当前应用的最大内存的1/8作为LruCache的容量
        lruCache = new LruCache<String, Bitmap>(maxSize){
            // 设置当前添加的图片的大小
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getRowBytes()*value.getHeight();
            }
        };
    }

    // 从内存缓存取图片
    public Bitmap getBitmap(String url){
        return lruCache.get(url);
    }

    // 在内存缓存存图片
    public void putBitmap(String url,Bitmap bitmap){
        lruCache.put(url, bitmap);
    }
}

2,本地缓存根据url,获取本地文件,把url进行md5加密,作为文件名,保证文件的正确性.

MD5加密工具类

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();
    }
}

本地缓存

public class LocalCacheUtil {

    private String CACHE_URl;
    private MemoryCacheUtil memoryCacheUtil;

    public LocalCacheUtil(MemoryCacheUtil memoryCacheUtil){
        // 初始化本地存储的路径
        CACHE_URl = Environment.getExternalStorageDirectory().getAbsoluteFile()+ "/test";
        this.memoryCacheUtil = memoryCacheUtil;
    }

    // 从本地sdcard取图片
    public Bitmap getBitmap(String url){
        // 根据url,获取本地文件,把url进行md5加密,作为文件名
        try {
            String fileName = MD5Encoder.encode(url);
            File file = new File(CACHE_URl, fileName);
            if(file.exists()){// 判断当前文件是否存在
                // 把当前文件转换成Bitmap对象
                Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
                // 需往内存中存一份
                memoryCacheUtil.putBitmap(url, bitmap);
                return bitmap;
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    // 往本地存图片的方法
    public void saveBitmap(String url,Bitmap bitmap){
        try {
            String fileName = MD5Encoder.encode(url);
            File file = new File(CACHE_URl, fileName);
            // 判断是否需要创建父目录
            File parentFile = file.getParentFile();
            if(!parentFile.exists()){
                parentFile.mkdirs();
            }
            // 把Bitmap对象保存到文件中 质量越高压缩速度越慢
            OutputStream stream = new FileOutputStream(file);
            bitmap.compress(CompressFormat.PNG, 100, stream);//第一个参数可以设置图片格式,第二个图片压缩质量,第三个为图片输出流
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3,网络缓存使用异步加载AsyncTask,使用其有二种原因:1,doInBackground运行在子线程,做网络请求耗时操作,避免主线程堵塞;2,onPreExecute和onPostExecute便于更新UI提高用户体验.

public class NetCacheUtil {
    private MemoryCacheUtil memoryCacheUtil;
    private LocalCacheUtil localCacheUtil;
    private ListView lv_image_list;

    public NetCacheUtil(MemoryCacheUtil memoryCacheUtil,LocalCacheUtil localCacheUtil){
        this.memoryCacheUtil = memoryCacheUtil;
        this.localCacheUtil = localCacheUtil;
    }


    public void display(ImageView imageView ,String url, ListView lv_image_list){
            this.lv_image_list = lv_image_list;
        new MyAsyncTask(imageView).execute(new Object[]{url,imageView});
    }
    class MyAsyncTask extends AsyncTask<Object, Void, Bitmap>{
        private ImageView imageView;
        private int position;
        public MyAsyncTask(ImageView imageView2) {
            position = (Integer) imageView2.getTag();
        }

        // 运行在主线程,做准备操作,在doInBackground之前,可以放置加载条提高用户体验
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        // 运行在子线程,做耗时操作
        @Override
        protected Bitmap doInBackground(Object... params) {
            // 获取url,下载图片
            String url = (String) params[0];
            // 获取ImageView
            imageView = (ImageView) params[1];
            try {
                // 下载图片
                HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
                conn.connect();// 连接网络
                // 获取响应码
                int resCode = conn.getResponseCode();
                if(resCode==200){// 访问成功
                    // 把服务器返回的输入流转换成Bitmap对象
                    Bitmap bitmap = BitmapFactory.decodeStream(conn.getInputStream());
                    // 保存到本地和内存
                    memoryCacheUtil.putBitmap(url, bitmap);
                    localCacheUtil.saveBitmap(url, bitmap);
                    return bitmap;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
        // 运行在主线程,更新界面,在doInBackground之后
        @Override
        protected void onPostExecute(Bitmap result) {
            // 判断线程开始时,那个位置是否还在Listview中
            ImageView view = (ImageView) lv_image_list.findViewWithTag(position);
            if(view!=null){
                view.setImageBitmap(result);
            }
            super.onPostExecute(result);
        }
    }
}

4,封装三级缓存形成ImageUtil,因内存缓存中取速度较快,所以先从内存缓存中取,取不到->本地缓存中取,取不到->网络缓存中取

public class ImageUtils {

    private MemoryCacheUtil memoryCacheUtil;
    private LocalCacheUtil localCacheUtil;
    private NetCacheUtil netCacheUtil;

    public ImageUtils(){
        memoryCacheUtil = new MemoryCacheUtil();
        localCacheUtil = new LocalCacheUtil(memoryCacheUtil);
        netCacheUtil = new NetCacheUtil(memoryCacheUtil,localCacheUtil);
    }

        public void display(ImageView imageView, String url, ListView lv_photo_list) {
        Bitmap bitmap = null;
        /**
         * 因内存缓存中取速度较快
         * 内存缓存中取,取不到->本地缓存中取,取不到->网络缓存中取
         */
        bitmap = memoryCacheUtil.getBitmap(url);//从内存缓存取图片
        if(bitmap!=null){
            imageView.setImageBitmap(bitmap);
            return;
        }
        bitmap = localCacheUtil.getBitmap(url);//从本地缓存取图片
        if(bitmap!=null){
            imageView.setImageBitmap(bitmap);
            return;
        }
        // 开启线程访问网络,下载图片,并且展示
        netCacheUtil.display(imageView, url,lv_photo_list);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值