• 关于三级缓存技术


    关于图片的处理,必不可少要用到三级缓存技术。

    什么是三级缓存?

    三级缓存一般分为内存--文件--网络三级缓存  

    内存(手机内存):内存相对于磁盘缓存,速度会快很多,但是缺点就是容量较小,不能存储大容量数据,且容易被系统回收。LruCache

    磁盘(SD卡):相对于内存来说存储空间很大,能够存储较多的数据。DiskLruCache(DiskLruCache是非Google官方编写,但获得官方认证的硬盘缓存类,该类没有限定在Android内,所以理论上Java应用也可以使用DiskLreCache来缓存。)

    网络:服务器端,通过HTTP请求获得。

    具体流程就是,同一张图片从网络获取一次,然后在本地缓存下来,之后加载同一张图片的时候就从缓存中去加载。
    先在内存中查找,找到就进行加载,否则去磁盘查找,找到将图片添加到内存中,加载显示,否则从网络加载,并且缓存到内存和磁盘,并返回。这就是完整的三级缓存过程。

    这里需要介绍的是内存缓存一共分为四类:强引用、软引用、弱引用和虚引用(后面我会再专门整理一篇博客的~)

    到这里三级缓存应该大概明白了吧,下面是我写的实现demo

    package simida.yz.com.imagecache.utils;
    
    import android.app.Activity;
    import android.app.DownloadManager;
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.os.Environment;
    import android.support.v4.util.LruCache;
    import android.util.Log;
    import android.widget.ImageView;
    
    import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    import okhttp3.Call;
    import okhttp3.Callback;
    import okhttp3.OkHttpClient;
    import okhttp3.Request;
    import okhttp3.Response;
    
    /**
     * Created by Administrator on 2016/12/2.
     */
    public class LoadImageCache {
        private Context mContext;
        //网络地址
        private String mImageUrl;
        //磁盘存储文件名
        private String mFileName;
        //内存缓存
        private LruCache<String, Bitmap> mLruCache;
        //磁盘目录(sd卡的私有cache目录)
        private String mFilePath;
    
    
        public LoadImageCache(Context context, String url) {
            this.mContext = context;
            this.mImageUrl = url;
            initLruCache();
            initFileCache();
        }
    
    
        public void loadBitmap(final ImageView imageView) {
            //现在内存中查找
            Bitmap bitmap = mLruCache.get(mImageUrl);
            if (bitmap != null) {
                Log.i("tag", "thumbnail from LruCache ");
                imageView.setImageBitmap(bitmap);
                return;
            } else {
                //去磁盘查找
                byte[] bytes = loadFromSD();
                if (bytes != null) {
                    //保存缩略图到cache
                    saveThumbnailToLruCache(bytes, 500, 300);
                    bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
                    Log.i("tag", "bitmap from sdcard ");
                    imageView.setImageBitmap(bitmap);
                    return;
                } else {
    
                    //网络加载 使用OKHTTP异步实现
                    OkHttpClient client = new OkHttpClient();
                    Request request = new Request.Builder().url(mImageUrl).build();
                    Call call = client.newCall(request);
                    call.enqueue(new Callback() {
                        @Override
                        public void onFailure(Call call, IOException e) {
    
                        }
    
                        @Override
                        public void onResponse(Call call, Response response) throws IOException {
                            byte[] fromNetWork = response.body().bytes();
                            //保存缩略图到cache
                            saveThumbnailToLruCache(fromNetWork, 500, 300);
                            //保存到sdcard
                            saveImageToSD(fromNetWork);
                            final Bitmap bitmap1 = BitmapFactory.decodeByteArray(fromNetWork, 0, fromNetWork.length);
                            Log.i("tag", "bitmap from network ");
                            ((Activity)mContext).runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    imageView.setImageBitmap(bitmap1);
                                }
                            });
    
                        }
                    });
                }
    
            }
        }
    
    
        //初始化磁盘缓存目录
        private void initFileCache() {
            //获取文件名称
            mFileName = mImageUrl.substring(mImageUrl.lastIndexOf("/") + 1);
            //判断sd卡是否挂载
            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
                //私有缓存目录
                mFilePath = mContext.getExternalCacheDir().getAbsolutePath();
            } else {
                Log.i("tag", "sdcard is error! ");
            }
    
        }
    
    
        //初始化内存缓存
        private void initLruCache() {
    
            if (mLruCache == null) {
                //获取运行时内存总大小
                long maxMemory = Runtime.getRuntime().maxMemory();
                //一般设置图片缓存为手机内存的1/8
                mLruCache = new LruCache<String, Bitmap>((int) (maxMemory / 8)) {
                    //用来衡量每张图片的大小,默认返回图片的数量
                    @Override
                    protected int sizeOf(String key, Bitmap value) {
                        //图片默认是ARGB_8888格式,每个像素占4个字节
    //                    int values = value.getWidth() * value.getHeight() * 4;
                        int values = value.getRowBytes() * value.getHeight();
                        return values;
                    }
    
                    //结合软引用使用时,会配合这个方法,现在已经基本不用软引用,不用考虑
                    @Override
                    protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {
                        super.entryRemoved(evicted, key, oldValue, newValue);
                    }
                };
            }
    
    
        }
    
        //保存图片到磁盘
        private void saveImageToSD(byte[] image) {
            BufferedOutputStream bos = null;
            try {
                bos = new BufferedOutputStream(new FileOutputStream(new File(mFilePath, mFileName)));
                bos.write(image, 0, image.length);
                bos.flush();
                bos.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                //关流
                try {
                    if (bos != null) {
                        bos.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
            Log.i("tag", "bitmap to sdcard ");
    
        }
    
        //磁盘查找
        private byte[] loadFromSD() {
            FileInputStream fis = null;
            BufferedInputStream bis = null;
            //内存流
            ByteArrayOutputStream baos = null;
            try {
                fis = new FileInputStream(new File(mFilePath, mFileName));
                bis = new BufferedInputStream(fis);
                baos = new ByteArrayOutputStream();
    
                byte[] bys = new byte[1024 * 8];
                int length = 0;
                while ((length = bis.read(bys)) != -1) {
                    baos.write(bys, 0, length);
                    baos.flush();
                }
                byte[] bytes = baos.toByteArray();
                return bytes;
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                return null;
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            } finally {
                //关流
                try {
                    if (baos != null) {
                        baos.close();
                    }
                    if (bis != null) {
                        bis.close();
                    }
                    if (fis != null) {
                        fis.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                Log.i("tag", "bitmap from sdcard ");
            }
        }
    
        //保存图片的缩略图到内存缓存,(二次采样技术)
        private void saveThumbnailToLruCache(byte[] image, int thumbWidth, int thumbHeight) {
            BitmapFactory.Options options = new BitmapFactory.Options();
            //只采图片的边界
            options.inJustDecodeBounds = true;
            //获取原图的高度和宽度
            BitmapFactory.decodeByteArray(image, 0, image.length, options);
            int width = options.outWidth;
            int height = options.outHeight;
    
            //计算缩略图宽高与原图宽高比例,取较大值作为最终缩放比例
            int size0 = (int) (thumbWidth / (float) width);
            int size1 = (int) (thumbHeight / (float) height);
            int size = size0 > size1 ? size0 : size1;
    
    
            options.inSampleSize = size;
            //设置图片格式
            options.inPreferredConfig = Bitmap.Config.RGB_565;
            //采图片全部
            options.inJustDecodeBounds = false;
    
            Bitmap bitmap = BitmapFactory.decodeByteArray(image, 0, image.length, options);
            mLruCache.put(mImageUrl, bitmap);
            Log.i("tag", "thumbnail to cache ");
        }
    
    }
    

      

    Activity和布局文件都比较简单,布局中只有一个imageView,实例化上面个工具类,调用loadBitmap方法即可,这里就不贴出来了。

    第一次打开时log信息:

    关闭后打开log信息:

    到这里三级缓存可以看明白了吧。

    这只是三级缓存的简单实现,实际项目中,有许多优秀的第三方框架已经将缓存机制优化的非常棒了,有兴趣的朋友可以继续看我的博客,最近没有工作,想要好好整理一下以前的东西了~再不整理都忘记啦。。。

  • 相关阅读:
    2018-2019-2 实验三 敏捷开发与XP实践
    计算机网络课外实验一级 20175319江野
    2018-2019-2 《Java程序设计》第9周学习总结
    MyCP(课下作业,必做)
    [NOIP2012] 疫情控制
    [SPOJ2021] Moving Pebbles
    谁能赢呢?
    [HEOI2014] 人人尽说江南好
    [笔记] 巴什博弈
    [SCOI2008] 着色方案
  • 原文地址:https://www.cnblogs.com/yangxiu/p/6126308.html
Copyright © 2020-2023  润新知