android中的图片三级缓存

三级缓存,顾名思义是有三个层级的操作:

1、内存缓存

2、本地缓存

3、网络

 

首先咱们来说说内存

内存包括:强引用、软引用、弱引用、虚引用。

强引用是默认的引用方式, 即使内存溢出,也不会回收。

软引用(softReference), 内存不够时, 会考虑回收。

弱引用 (WeakReference)内存不够时, 更会考虑回收。

虚引用(PhantomReference) 内存不够时, 最优先考虑回收!

一般我们常用到的引用就是强引用,比如引用创建一个成员变量里面的引用。对于GC来说, SoftReference的强度明显低于 SrongReference。SoftReference修饰的引用,其告诉GC:我是一个 软引用,当内存不足的时候,我指向的这个内存是可以给你释放掉的。一般对于这种占用内存资源比较大的,又不是必要的变量;或者一些占用大量内存资源的一些缓存的变量,就需要考虑 SoftReference。对于GC来说, WeakReference 的强度又明显低于 SoftReference 。 WeakReference 修饰的引用,其告诉GC:我是一个弱引用,对于你的要求我没有话说,我指向的这个内存是可以给你释放掉的。虚引用其实和上面讲到的各种引用不是一回事的,他主要是为跟踪一个对象何时被GC回收。在android里面也是有用到的:FileCleaner.java 。这些避免内存溢出的引用方式在Android 2.3+的版本上已经不再起太大作用, 因为垃圾回收器会频繁回收非强引用的对象, Android官方建议使用LRUCache。所以当我们用软引用进行内存缓存时会发现内存中的资源会被系统频繁回收。最终是从本地进行读数据。

LRUCache(Least Recently Used),就是近期最少使用的算法,核心思想是当缓存满时,会优先淘汰那些近期最少使用的缓存对象。LruCache中维护了一个集合LinkedHashMap,该LinkedHashMap是以访问顺序排序的。当调用put()方法时,就会在结合中添加元素,并调用trimToSize()判断缓存是否已满,如果满了就用LinkedHashMap的迭代器删除队尾元素,即近期最少访问的元素。当调用get()方法访问缓存对象时,就会调用LinkedHashMap的get()方法获得对应集合元素,同时会更新该元素到队头。

 

创建一个管理类BitmapUtils

import android.graphics.Bitmap;
import android.util.Log;
import android.widget.ImageView;

import com.wisdtour.interact.R;

public class BitmapUtils {
    private NetCacheUtils mNetCacheUtils;
    private LocalCacheUtils mLocalCacheUtils;
    private MemoryCacheUtils mMemoryCacheUtils;

    public BitmapUtils(){
        mMemoryCacheUtils=new MemoryCacheUtils();
        mLocalCacheUtils=new LocalCacheUtils();
        mNetCacheUtils=new NetCacheUtils(mLocalCacheUtils,mMemoryCacheUtils);
    }

    /**
     * 用来三级缓存显示图片
     * @param ivPic
     * @param url
     */
    public void disPlay(ImageView ivPic, String url) {
        ivPic.setImageResource(R.drawable.s);
        Bitmap bitmap;
        //  1. 内存缓存 速度很快不浪费流量   优先
        bitmap=mMemoryCacheUtils.getBitmapFromMemory(url);
        if (bitmap!=null){
            ivPic.setImageBitmap(bitmap);
            Log.e("TAG", "从内存获取图片啦");
            return;
        }

        //本地缓存  速度快 不浪费流量    其次
        bitmap = mLocalCacheUtils.getBitmapFromLocal(url);
        if(bitmap !=null){
            ivPic.setImageBitmap(bitmap);
            Log.e("TAG", "从本地获取图片啦");
            //从本地获取图片后,保存至内存中
            mMemoryCacheUtils.setBitmapToMemory(url,bitmap);
            return;
        }
        //网络缓存  速度慢浪费流量      最后
        mNetCacheUtils.getBitmapFromNet(ivPic,url);
    }


}

依次创建三个类

MemoryCacheUtils 

import android.graphics.Bitmap;
import android.util.LruCache;

public class MemoryCacheUtils {
    private LruCache<String, Bitmap> mMemoryCache;
    public MemoryCacheUtils(){
        long maxMemory = Runtime.getRuntime().maxMemory()/8;//得到手机最大允许内存的1/8,即超过指定内存,则开始回收
        //需要传入允许的内存最大值,虚拟机默认内存16M,真机不一定相同
        mMemoryCache=new LruCache<String,Bitmap>((int) maxMemory){
            //用于计算每个条目的大小
            @Override
            protected int sizeOf(String key, Bitmap value) {
                int byteCount = value.getByteCount();
                return byteCount;
            }
        };
    }
    /**
     * 从内存中读图片
     * @param url
     */
    public Bitmap getBitmapFromMemory(String url) {
        //Bitmap bitmap = mMemoryCache.get(url);//1.强引用方法
          /*2.弱引用方法
          SoftReference<Bitmap> bitmapSoftReference = mMemoryCache.get(url);
          if (bitmapSoftReference != null) {
              Bitmap bitmap = bitmapSoftReference.get();
              return bitmap;
          }
          */
        if(url==null||"".equals(url)){
            return null;
        }
        Bitmap bitmap = mMemoryCache.get(url);

        return bitmap;

    }
    /**
     * 往内存中写图片
     * @param url
     * @param bitmap
     */
    public void setBitmapToMemory(String url, Bitmap bitmap) {
        //mMemoryCache.put(url, bitmap);//1.强引用方法
          /*2.弱引用方法
          mMemoryCache.put(url, new SoftReference<>(bitmap));
          */
        mMemoryCache.put(url,bitmap);
    }

}

本地缓存 LocalCacheUtils 

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class LocalCacheUtils {
    private static final String CACHE_PATH= Environment.getExternalStorageDirectory().getAbsolutePath()+"/my/images";
    /**
     * 从本地读取图片
     * @param url
     */
    public Bitmap getBitmapFromLocal(String url){
        String fileName = null;//把图片的url当做文件名,并进行MD5加密
        try {
            fileName = MD5Encoder.encode(url);    //这里加不加密无所谓
            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 setBitmapToLocal(String url, Bitmap bitmap){
        try {

            String fileName = MD5Encoder.encode(url);//把图片的url当做文件名,并进行MD5加密
            File file=new File(CACHE_PATH,fileName);

            //通过得到文件的父文件,判断父文件是否存在
            File parentFile = file.getParentFile();
            if (!parentFile.exists()){
                parentFile.mkdirs();
            }
            //把图片保存至本地
            bitmap.compress(Bitmap.CompressFormat.JPEG,100,new FileOutputStream(file));
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}

 网络缓存NetCacheUtils 

import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.os.AsyncTask;
import android.os.Build;
import android.view.View;
import android.widget.ImageView;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;

public class NetCacheUtils {
    private LocalCacheUtils mLocalCacheUtils;
    private MemoryCacheUtils mMemoryCacheUtils;

    public NetCacheUtils(LocalCacheUtils localCacheUtils, MemoryCacheUtils memoryCacheUtils) {
        mLocalCacheUtils = localCacheUtils;
        mMemoryCacheUtils = memoryCacheUtils;
    }

    public NetCacheUtils() {

    }

    /**
     * 从网络下载图片
     *
     * @param ivPic 显示图片的imageview
     * @param url   下载图片的网络地址
     */
    public void getBitmapFromNet(ImageView ivPic, String url) {
        new BitmapTask().execute(ivPic, url);//启动AsyncTask

    }


    public void getBitmapFromNet(View ivPic, String url) {
        new BitmapTask_view().execute(ivPic, url);//启动AsyncTask

    }

    public Bitmap getBitmapFromNet(final String url) {
        //启动AsyncTask
        return null;
    }

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

        private ImageView ivPic;
        private String url;

        /**
         * 后台耗时操作,存在于子线程中
         *
         * @param params
         * @return
         */
        @Override
        protected Bitmap doInBackground(Object[] params) {
            ivPic = (ImageView) params[0];
            url = (String) params[1];

            return downLoadBitmap(url);
        }

        /**
         * 更新进度,在主线程中
         *
         * @param values
         */
        @Override
        protected void onProgressUpdate(Void[] values) {
            super.onProgressUpdate(values);
        }

        /**
         * 耗时方法结束后执行该方法,主线程中
         *
         * @param result
         */
        @Override
        protected void onPostExecute(Bitmap result) {
            if (result != null) {
                ivPic.setImageBitmap(result);
                System.out.println("从网络缓存图片啦.....");

                //从网络获取图片后,保存至本地缓存
                mLocalCacheUtils.setBitmapToLocal(url, result);
                //保存至内存中
                mMemoryCacheUtils.setBitmapToMemory(url, result);

            }
        }
    }

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

        private View ivPic;
        private String url;

        /**
         * 后台耗时操作,存在于子线程中
         *
         * @param params
         * @return
         */
        @Override
        protected Bitmap doInBackground(Object[] params) {
            ivPic = (View) params[0];
            url = (String) params[1];

            return downLoadBitmap(url);
        }

        /**
         * 更新进度,在主线程中
         *
         * @param values
         */
        @Override
        protected void onProgressUpdate(Void[] values) {
            super.onProgressUpdate(values);
        }

        /**
         * 耗时方法结束后执行该方法,主线程中
         *
         * @param result
         */
        @Override
        protected void onPostExecute(Bitmap result) {
            if (result != null) {
                //ivPic.setImageBitmap(result);
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                    //Android系统大于等于API16,使用setBackground
                    ivPic.setBackground(new BitmapDrawable(result));
                } else {
                    //Android系统小于API16,使用setBackground
                    ivPic.setBackgroundDrawable(new BitmapDrawable(result));
                }


                System.out.println("从网络缓存图片啦.....");

                //从网络获取图片后,保存至本地缓存
                mLocalCacheUtils.setBitmapToLocal(url, result);
                //保存至内存中
                mMemoryCacheUtils.setBitmapToMemory(url, result);

            }
        }
    }

    /**
     * 网络下载图片
     *
     * @param url
     * @return
     */
    public Bitmap downLoadBitmap(String url) {
        HttpURLConnection conn = null;
        try {
            conn = (HttpURLConnection) new URL(url).openConnection();
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(5000);
            conn.setRequestMethod("GET");

            int responseCode = conn.getResponseCode();
            if (responseCode == 200) {
                //图片压缩
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inSampleSize = 2;//宽高压缩为原来的1/2
                options.inPreferredConfig = Bitmap.Config.ARGB_4444;

                //Bitmap bitmap = BitmapFactory.decodeStream(conn.getInputStream(),null,options);
                Bitmap bitmap = BitmapFactory.decodeStream(conn.getInputStream());
                return bitmap;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
        } finally {
            if (conn != null) {
                conn.disconnect();
            }
        }

        return null;
    }

}

MD5

import java.security.MessageDigest;

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

使用

BitmapUtils bitmapUtils = new BitmapUtils();
//bitmapUtils.disPlay(test,"http://ww4.sinaimg.cn/large/006uZZy8jw1faic21363tj30ci08ct96.jpg");
bitmapUtils.disPlay(test,url);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值