android三级缓存详解

为什么需要图片缓存

android默认给每个应用只分配16M的内存,所以如果加载过多的图片,为了防止内存溢出,应该将图片缓存起来。图片的三级缓存分别是:

    内存缓存
    本地缓存
    网络缓存

其中,内存缓存应优先加载,它速度最快;本地缓存次优先加载,它速度也快;网络缓存不应该优先加载,它走网络,速度慢且耗流量。(总的来说由快到慢)

三级缓存的具体实现
网络缓存

    根据图片的url去加载图片
    在本地和内存中缓存

    public class NetCacheUtils { 

        private LocalCacheUtils mLocalCacheUtils;
        private MemoryCacheUtils mMemoryCacheUtils;

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

        /** * 从网络下载图片 * * @param ivPic * @param url */
        public void getBitmapFromNet(ImageView ivPic, String url) {
            new BitmapTask().execute(ivPic, url);// 启动AsyncTask,
                                                    // 参数会在doInbackground中获取
        }

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

            private ImageView ivPic;
            private String url;

            /** * 后台耗时方法在此执行, 子线程 */
            @Override
            protected Bitmap doInBackground(Object... params) {
                ivPic = (ImageView) params[0];
                url = (String) params[1];

                ivPic.setTag(url);// 将url和imageview绑定

                return downloadBitmap(url);
            }

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

            /** * 耗时方法结束后,执行该方法, 主线程 */
            @Override
            protected void onPostExecute(Bitmap result) {
                if (result != null) {
                    String bindUrl = (String) ivPic.getTag();

                    if (url.equals(bindUrl)) {
  // 确保图片设定给了正确的imageview
                        ivPic.setImageBitmap(result);
                        mLocalCacheUtils.setBitmapToLocal(url, result);// 将图片保存在本地
                        mMemoryCacheUtils.setBitmapToMemory(url, result);// 将图片保存在内存
                        System.out.println("从网络缓存读取图片啦...");
                    }
                }
            }
        }

        /** * 下载图片 * * @param url * @return */
        private Bitmap downloadBitmap(String url) {

            HttpURLConnection conn = null;
            try {
                conn = (HttpURLConnection) new URL(url).openConnection();

                conn.setConnectTimeout(5000);
                conn.setReadTimeout(5000);
                conn.setRequestMethod("GET");
                conn.connect();

                int responseCode = conn.getResponseCode();
                if (responseCode == 200) {
                    InputStream inputStream = conn.getInputStream();

                    //图片压缩处理
                    BitmapFactory.Options option = new BitmapFactory.Options();
                    option.inSampleSize = 2;//宽高都压缩为原来的二分之一, 此参数需要根据图片要展示的大小来确定
                    option.inPreferredConfig = Bitmap.Config.RGB_565;//设置图片格式

                    Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, option);
                    return bitmap;
                }

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                conn.disconnect();
            }

            return null;
        }
    }

本地缓存

两个方法:设置本地缓存,获取本地缓存
public class LocalCacheUtils { 

        public static final String CACHE_PATH = Environment
                .getExternalStorageDirectory().getAbsolutePath() + "/local_cache";

        /** * 从本地sdcard读图片 */
        public Bitmap getBitmapFromLocal(String url) {
            try {
                String fileName = MD5Encoder.encode(url);
                File file = new File(CACHE_PATH, fileName);

                if (file.exists()) {
                    Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(
                            file));
                    return bitmap;
                }

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

            return null;
        }

        /** * 向sdcard写图片 * * @param url * @param bitmap */
        public void setBitmapToLocal(String url, Bitmap bitmap) {
            try {
                String fileName = MD5Encoder.encode(url);

                File file = new File(CACHE_PATH, fileName);

                File parentFile = file.getParentFile();
                if (!parentFile.exists()) {
  // 如果文件夹不存在, 创建文件夹
                    parentFile.mkdirs();
                }

                // 将图片保存在本地
                bitmap.compress(CompressFormat.JPEG, 100,
                        new FileOutputStream(file));
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

内存缓存

两个方法:设置内存缓存,获取内存缓存
问题:
    如果使用HashMap存储图片时,当图片越来越多时,会导致内存溢出,因为它是强引用,java的垃圾回收器不会回收。
    如若改成软引用SoftReference(内存不够时,垃圾回收器会考虑回收),仍有一个问题:在android2.3+, 系统会优先将SoftReference的对象提前回收掉, 即使内存够用。
解决办法:可以用LruCache来解决上述内存不回收或提前回收的问题。least recentlly use 最少最近使用算法 它会将内存控制在一定的大小内, 超出最大值时会自动回收, 这个最大值开发者自己定
 public class MemoryCacheUtils { 

            // private HashMap<String, SoftReference<Bitmap>> mMemoryCache = new
            // HashMap<String, SoftReference<Bitmap>>();
            private LruCache<String, Bitmap> mMemoryCache;

            public MemoryCacheUtils() {
                long maxMemory = Runtime.getRuntime().maxMemory() / 8;// 模拟器默认是16M
                mMemoryCache = new LruCache<String, Bitmap>((int) maxMemory) {
                    @Override
                    protected int sizeOf(String key, Bitmap value) {
                        int byteCount = value.getRowBytes() * value.getHeight();// 获取图片占用内存大小
                        return byteCount;
                    }
                };
            }

            /** * 从内存读 * * @param url */
            public Bitmap getBitmapFromMemory(String url) {
                // SoftReference<Bitmap> softReference = mMemoryCache.get(url);
                // if (softReference != null) { 
                // Bitmap bitmap = softReference.get();
                // return bitmap;
                // }
                return mMemoryCache.get(url);
            }

            /** * 写内存 * * @param url * @param bitmap */
            public void setBitmapToMemory(String url, Bitmap bitmap) {
                // SoftReference<Bitmap> softReference = new
                // SoftReference<Bitmap>(bitmap);
                // mMemoryCache.put(url, softReference);
                mMemoryCache.put(url, bitmap);
            }
        }

图片压缩

//图片压缩处理(在从网络获取图片的时候就进行压缩)
    BitmapFactory.Options option = new BitmapFactory.Options();
    option.inSampleSize = 2;//宽高都压缩为原来的二分之一, 此参数需要根据图片要展示的大小来确定
    option.inPreferredConfig = Bitmap.Config.RGB_565;//设置图片格式
    Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, option);

转载出处:http://blog.csdn.net/sinat_20645961/article/details/46325243

    原文作者:过去式的美好
    原文地址: https://blog.csdn.net/u012138137/article/details/50921209
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞