Android图片缓存的基本思路整理

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/immrwk/article/details/79487525

缓存方式主要分为网络缓存,内存缓存,文件缓存

这里简单介绍一下后面两种的思路,使用内存缓存和使用文件缓存

  • 缓存的基本原理,将从网络中得到的图片存储在本地,避免再次使用时从网络重新加载,可以增快加载速度,减少网络流量的消耗

内存缓存

内存缓存主要分为两种方式
1. 使用LruCache
2. 使用HashMap
这两种方式一般结合使用
LruCache是Android给我们提供的工具类(内部实现用的LinkedHashMap),使用LruCache时,需给LruCache设置一个maxsize,当缓存图片的总大小超过maxsize之后,会执行LruCache的entryRemoved方法,此时可将被移除的oldValue存入HashMap中.
代码如下:

        mLruCache = new LruCache<String, Bitmap>(memorySize) {

            // 必须重写此方法,来测量Bitmap的大小
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getRowBytes() * value.getHeight();
            }

            @Override
            protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {
                // 当LruCache的内存容量满的时候会调用,将oldValue的元素移除出来腾出空间给新的元素加入
                if (!TextUtils.isEmpty(key) && oldValue != null && !oldValue.isRecycled()) {
                    mWeakCache.put(key, new WeakReference<Bitmap>(oldValue));
                }
            }

        };

HashMap的key采用和LruCache相同的key,value使用SoftReference或WeakReference.

SoftReference会在内存不足时被GC回收掉,WeakReference当GC一开始工作就会将其回收。

这两种一般会封装到一起使用,封装之后的使用统一的数据处理方法
put() put数据时,首先检查数据的key,value合法性,是否为null等等,2可以根据情况判断将要被缓存的Bitmap大小是否超过我们的单次最大限制(自己根据项目定)

    public void put(String key, Bitmap value) {
        if (TextUtils.isEmpty(key) || value == null) {
            return;
        }
        int size = value.getRowBytes() * value.getHeight();// 4 * 宽 * 高
        if (size > 1024 * 1024 * 3) {
            return;
        }
        mLruCache.put(key, value);
    }

get() get数据时,会首先根据key从LruCache中取get想要的数据,成功获取即返回,获取不到时再从HashMap中进行查找get

    public Bitmap get(String key) {
        if (TextUtils.isEmpty(key)) {
            return null;
        }

        Bitmap bitmap = mLruCache.get(key);
        if (bitmap != null) {
            return bitmap;
        }

        WeakReference<Bitmap> reference = mWeakCache.get(key);
        if (reference != null) {
            return reference.get();
        }
        return null;
    }

remove()和clear() 执行remove时,需要对应执行LruCache和HashMap的remove和clear方法

    public void remove(String key) {
        if (TextUtils.isEmpty(key)) {
            return;
        }

        mLruCache.remove(key);
        mWeakCache.remove(key);
    }

    public void clear() {
        mLruCache.evictAll();
        mWeakCache.clear();
    }

文件缓存

主要使用DiskLruCache
将从网络上下载的图片保存在手机SD卡中,以图片url的MD5值作为保存的文件名(key)
代码如下:

public class DiscCache {
    private static final int MAX = 50 * 1024 * 1024;

    private Context mContext;
    private DiskLruCache mDiskLruCache;

    public DiscCache(Context context) {
        mContext = context;
        String path = FileUtils.getBitmapCachePath(mContext);
        final File cacheDir = new File(path);
        if (!cacheDir.exists()) {
            cacheDir.mkdirs();
        }
        ThreadManager.startRun(new Runnable() {
            @Override
            public void run() {
                mDiskLruCache = DiskLruCache.open(cacheDir, 1, 1, MAX);
            }
        });
    }

    /**
     * 增加获取缩略图Bitmap
     *
     * @param url
     * @param config
     * @return
     */
    public Bitmap getThumbnailBitmap(String url, BitmapConfig config) {
        Bitmap bitmap = getBitmapFromDisk(url, config);
        try {
            bitmap = LetvThumbnailUtils.getThumbnailBitmap(url);

            if (bitmap == null) {
                NativeThumbnail nativeThumbnail = new NativeThumbnail(url);
                bitmap = nativeThumbnail.getVideoThumbnail(96, 96, 10);
            }

            if (bitmap != null && mDiskLruCache != null) {
                DiskLruCache.Editor editor = mDiskLruCache.edit(MD5.MD5Encode(url));
                if (editor != null) {
                    OutputStream outputStream = editor.newOutputStream(0);
                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
                    editor.commit();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return bitmap;
    }

    /**
     * 从网络获取bitmap
     *
     * @param url
     * @param config
     * @return
     */
    public Bitmap getBitmapFromNetwork(String url, BitmapConfig config) {
        try {
            DiskLruCache.Editor editor = null;
            if (mDiskLruCache != null) {
                editor = mDiskLruCache.edit(MD5.MD5Encode(url));
            }
            if (editor == null) {
                return getBitmapFromNetworkWithoutLru(url, config);
            }

            OutputStream outputStream = editor.newOutputStream(0);
            if (DownloaderFromHttp.download(url, outputStream)) {
                editor.commit();
            } else {
                editor.abort();
            }
            return getBitmapFromDisk(url, config);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 从网络获取bitmap
     *
     * @param url
     * @param config
     * @return
     */
    private Bitmap getBitmapFromNetworkWithoutLru(String url, BitmapConfig config) {
        byte[] data = DownloaderFromHttp.download(url);
        if (data != null && data.length > 0) {
            ImgFileManager.saveImage(mContext, url, data);

            if (config == null) {
                return BitmapDecoder.decodeSampledBitmapFromByteArray(data, 0, data.length);
            } else {
                return BitmapDecoder
                        .decodeSampledBitmapFromByteArray(data, 0, data.length, config.width, config.height);
            }

        }

        return null;
    }

    /**
     * 从磁盘获取bitmap
     *
     * @param key
     * @return
     */
    public Bitmap getBitmapFromDisk(String key, BitmapConfig config) {
        Snapshot snapshot = null;
        try {
            if (mDiskLruCache != null)
                snapshot = mDiskLruCache.get(MD5.MD5Encode(key));
        } catch (IOException e1) {
            e1.printStackTrace();
        }
        if (snapshot == null) {
            return getBitmapFromDiskWithoutLru(key, config);
        }

        FileInputStream fis = null;
        ByteArrayOutputStream bos = null;

        try {
            fis = (FileInputStream) snapshot.getInputStream(0);
            if (fis == null) {
                return getBitmapFromDiskWithoutLru(key, config);
            }

            bos = new ByteArrayOutputStream();
            byte[] b = new byte[1024];
            int n;
            while ((n = fis.read(b)) != -1) {
                bos.write(b, 0, n);
            }
            byte[] data = bos.toByteArray();

            if (data == null)
                return null;

            if (config == null) {
                return BitmapDecoder.decodeSampledBitmapFromByteArray(data, 0, data.length);
            } else {
                return BitmapDecoder
                        .decodeSampledBitmapFromByteArray(data, 0, data.length, config.width, config.height);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (bos != null)
                    bos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }

            try {
                if (fis != null)
                    fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return null;
    }

    /**
     * 从磁盘获取bitmap
     *
     * @param key
     * @return
     */
    private Bitmap getBitmapFromDiskWithoutLru(String key, BitmapConfig config) {
        byte[] data = ImgFileManager.getImage(mContext, key);
        if (data == null)
            return null;

        if (config == null) {
            return BitmapDecoder.decodeSampledBitmapFromByteArray(data, 0, data.length);
        } else {
            return BitmapDecoder.decodeSampledBitmapFromByteArray(data, 0, data.length, config.width, config.height);
        }
    }

    /**
     * 将缓存记录同步到journal文件中。
     */
    public void fluchCache() {
        if (mDiskLruCache != null) {
            try {
                mDiskLruCache.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void closeCache() {
        if (mDiskLruCache != null) {
            try {
                mDiskLruCache.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/immrwk/article/details/79487525
今日推荐