图片三级缓存

我们在开发中用了许多加载图片的框架都封装了缓存机制,图片的三级缓存的核心类就是LruCache类,尝试手写三级缓存工具类:

/**
 * 自定义的加载网络图片工具:三级缓存
 * @author wangk
 *
 */
public class MyBitmapUtils {

    private Context context;

    private LruCache<String, Bitmap> lruCache;

    private File rootFile;//本地缓存根目录

    private ExecutorService executorService;

    public MyBitmapUtils(Context context) {
        this.context = context;
        /**
         * maxSize:lruCache能管理的最大内存,此处设置为最大内存的1/8
         */
        int maxSize = (int) (Runtime.getRuntime().maxMemory()/8);//Runtime.getRuntime().maxMemory()当前应用可使用的最大内存
        lruCache = new LruCache<String, Bitmap>(maxSize){
            /**
             * 当前存储的对象,bitmap,如何计算大小
             */
            @Override
            protected int sizeOf(String key, Bitmap bitmap) {
                return bitmap.getRowBytes() * bitmap.getHeight();//每一行的字节个数*高度 =  bitmap的大小
            }
        };
        //本地缓存到data/data
        rootFile = context.getFilesDir();

        executorService = Executors.newFixedThreadPool(3);//创建固定大小的线程池,内部维护了3个线程
    }
    /**
     * 展示网络图片
     * @param image : 展示的空间
     * @param imageUrl: 图片的url
     */
    public void display(ImageView image, String imageUrl) {
        /**
         * 三级缓存  (图片)
         * 1.内存缓存 HashMap <key,value> key:图片url,value:bitmap
         *          v4:LruCache 类似hashmap <key,value>  lru算法:less recent use,最少最近使用
         * 2.本地缓存 保存sd卡,mnt/sdcard/zhbj_10/image/xxx.png
         *          xxx:图片名称,一般以图片的 url+md5 命名
         *             url:唯一,还能通过url获取本地缓存图片
         *             md5加密:为了避免url的特殊字符
         * 3.网络缓存
         *      
         * 使用步骤: 遵循原则:优先获取加载速度最快的缓存数据
         * 1.从内存中获取,如果获取到图片,直接展示。如果获取不到,从本地缓存获取
         * 2.从本地缓存中获取,如果获取到图片,先加载到内存,然后展示。如果获取不到,从网络获取
         * 3.从网络获取,如果获取到图片,加载到内存中,然后展示,保存到本地。
         */
        //1.从内存中获取图片
        Bitmap cacheBitmap = lruCache.get(imageUrl);
        if(cacheBitmap!=null){
            image.setImageBitmap(cacheBitmap);
            System.out.println("从内存中获取");
            return ;
        }
        //2. 从本地获取
        String imageName = MD5Encoder.encode(imageUrl);//url+md5加密
        File cacheFile = new File(rootFile, imageName);
        if(cacheFile.exists() && cacheFile.length()!=0){
            //加载到内存中,展示
            Bitmap decodeFileBitmap = BitmapFactory.decodeFile(cacheFile.getAbsolutePath());
            lruCache.put(imageUrl, decodeFileBitmap);
            image.setImageBitmap(decodeFileBitmap);
            System.out.println("从本地中获取");
            return;
        }
        //3.从网络获取
        int position = (Integer) image.getTag();
        executorService.execute(new DownLoadRunnable(image,imageUrl,position));
        System.out.println("从网络获取");

    }
    class DownLoadRunnable implements Runnable{
        private ImageView image;
        private String imageUrl;
        private int position;
        /**
         * 
         * @param image
         * @param imageUrl
         * @param position:请求的位置
         */
        public DownLoadRunnable(ImageView image, String imageUrl, int position) {
            this.image = image;
            this.imageUrl = imageUrl;
            this.position = position;
        }

        @Override
        public void run() {
            try {
                SystemClock.sleep(1000);
                //从网络获取:HttpUrlConnection获取网络图片
                URL url = new URL(imageUrl);
                HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
                //设置超时时间
                httpURLConnection.setConnectTimeout(5*1000);
                //设置请求方式
                httpURLConnection.setRequestMethod("GET");
                //获取响应码
                int responseCode = httpURLConnection.getResponseCode();
                if(responseCode == 200){//请求成功
                    InputStream inputStream = httpURLConnection.getInputStream();
                    final Bitmap decodeStreamBitmap = BitmapFactory.decodeStream(inputStream);
                    //保存到内存
                    lruCache.put(imageUrl, decodeStreamBitmap);
                    //保存到本地(bitmap对象如何转换成本地文件)
                    /**
                     * compress:压缩
                     * format:压缩格式:png、jgp
                     * quality:压缩质量:0-100,0-完全压缩,100-不压缩
                     * outputStream:输出流,写到本地
                     */
                    File cacheFile = new File(rootFile, MD5Encoder.encode(imageUrl));
                    OutputStream ops = new FileOutputStream(cacheFile);
                    decodeStreamBitmap.compress(CompressFormat.PNG, 100, ops);
                    //展示
                    MainActivity mainActivity = (MainActivity) context;
                    mainActivity.runOnUiThread(new Runnable()//Runnable在子线程还是主线程中运行,主要看调用者
                    {

                        @Override
                        public void run() {
                            int currentPosition = (Integer) image.getTag();
                            //请求的位置如果是当前显示在屏幕上的位置
                            if(position == currentPosition){
                                image.setImageBitmap(decodeStreamBitmap);
                            }
                        }
                    });

                }

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

        }

    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值