某宅的Android学习笔记(二)——图片三级缓存

图片三级缓存的重要性

 很多时候我们都需要从网络上下载图片,如果在图片很多的情况下,每次启动app都要从网上下载,就会造成流量的浪费,影响用户的体验。因此,要利用缓存来避免图片的重复加载。

图片缓存方式

 所谓三级缓存,即:

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

 在加载图片时,优先访问内存缓存,如果没有结果,再去访问本地文件;如果都没有结果,才去从网络下载图片。并且在图片下载之后,要将图片缓存到内存和本地。
 其实严格来说网络并不能算是缓存,不过这里姑且这么叫吧。

依次实现三级缓存

1.本地缓存

 private static final String LOCAL_CACHE_PATH =
 Environment.getExternalStorageDirectory().getAbsolutePath() + "/ImgCache";//本地文件保存路径

/**
 * 从本地获取图片
 */
private Bitmap getBitmapFromLocalCache(String url) {
    Bitmap bitmap = null;
    String fileName = url;
    File file = new File(LOCAL_CACHE_PATH, fileName);//将url作为文件名
    try {
        bitmap = BitmapFactory.decodeStream(new FileInputStream(file));
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    return bitmap;
}

/**
 * 将图片保存到本地
 */
private void addBitmapToLocalCache(String url, Bitmap bitmap) {
    String fileName = url;
    File file = new File(LOCAL_CACHE_PATH, fileName);//将url作为文件名
    File parentFile = file.getParentFile();
    if (!parentFile.exists()) {//判断父文件是否存在
        parentFile.mkdirs();
    }
    try {
        //保存图片
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, new FileOutputStream(file));
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }

2.内存缓存

 这里使用LruCache()——近期最少使用算法来控制缓存的大小,以避免出现OOM。

private static LruCache<String, Bitmap> memoryCaches;

//私有化构造方法以保证对象全局唯一性
private ImageLoader(ListView listView) {
    this.listView = listView;
    tasks = new HashSet<>();
    //设定缓存区的大小
    if (memoryCaches == null) {
        int maxMemory = (int) Runtime.getRuntime().maxMemory();
        int cacheSize = maxMemory / 4;
        memoryCaches = new LruCache<String, Bitmap>(cacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getByteCount();
            }
        };
    }
}

//单例化ImageLoader
public static ImageLoader getImageLoader(ListView mListView) {
    imageLoader = new ImageLoader(mListView);
    return imageLoader;
}

 在设定好内存缓存大小之后,同样需要添加相应的方法。

/**
 * 从内存缓存获取bitmap
 */
private Bitmap getBitmapFromLruCache(String url) {
    return memoryCaches.get(url);
}

/**
 * 向内存缓存中添加bitmap
 */
private void addBitmapToLruCache(String url, Bitmap bitmap) {
    if (getBitmapFromLruCache(url) == null) {
        memoryCaches.put(url, bitmap);
    }
}

3.网络缓存

 从网络下载图片,通过AsyncTask来进行异步加载。

/**
 * 利用AsyncTask来完成异步加载图片
 */
private class imgAsyncTask extends AsyncTask<String, Void, Bitmap> {

    private String url;

    public imgAsyncTask(String url) {
        this.url = url;
    }

    @Override
    protected Bitmap doInBackground(String... params) {
        String url = params[0];
        Bitmap bitmap = getBitmapFromUrl(url);
        if (bitmap != null) {
            addBitmapToLruCache(url, bitmap);//将bitmap添加到缓存中
            addBitmapToLocalCache(url, bitmap);//将bitmap添加到本地
        }
        return bitmap;
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        super.onPostExecute(bitmap);
        ImageView imageView = (ImageView) listView.findViewWithTag(url);
        if (imageView != null && bitmap != null) {
            imageView.setImageBitmap(bitmap);
        }
        tasks.remove(this);
    }
}

/**
 * 开启网络请求
 * 根据url来获取bitmap
 */
private Bitmap getBitmapFromUrl(String urlString) {

    Bitmap bitmap = null;
    HttpURLConnection connection = null;
    try {
        URL mUrl = new URL(urlString);
        connection = (HttpURLConnection) mUrl.openConnection();
        bitmap = BitmapFactory.decodeStream(connection.getInputStream());
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (connection != null) {
            connection.disconnect();
        }
    }
    return bitmap;
}

 这样三级缓存就写好了,相应的加载方法如下:

        //优先从内存获取图片,若不存在则从本地获取
        Bitmap bitmap = getBitmapFromLruCache(imgUrl);
        if (bitmap == null) {
            bitmap = getBitmapFromLocalCache(imgUrl);
        }
        //若bitmap存在,直接设置
        if (imageView != null && bitmap != null) {
            imageView.setImageBitmap(bitmap);
        } else {
            //若不存在,开启线程从网络下载
            imgAsyncTask mTask = new imgAsyncTask(imgUrl);
            mTask.execute(imgUrl);
            tasks.add(mTask);
        }

最后附上自己项目的地址:https://github.com/Zhai-Wang/KanZhiHu,欢迎各路大神指正!

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值