图片三级缓存

为什么要使用三级缓存

如今的 Android App 经常会需要网络交互,通过网络获取图片是再正常不过的事了
假如每次启动的时候都从网络拉取图片的话,势必会消耗很多流量。在当前的状况下,对于非wifi用户来说,流量还是很贵的,一个很耗流量的应用,其用户数量级肯定要受到影响
特别是,当我们想要重复浏览一些图片时,如果每一次浏览都需要通过网络获取,流量的浪费可想而知
所以提出三级缓存策略,通过网络、本地、内存三级缓存图片,来减少不必要的网络交互,避免浪费流量

什么是三级缓存

网络缓存, 不优先加载, 速度慢,浪费流量
本地缓存, 次优先加载, 速度快
内存缓存, 优先加载, 速度最快

三级缓存原理

首次加载 Android App 时,肯定要通过网络交互来获取图片,之后我们可以将图片保存至本地SD卡和内存中
之后运行 App 时,优先访问内存中的图片缓存,若内存中没有,则加载本地SD卡中的图片
总之,只在初次访问新内容时,才通过网络获取图片资源

代码实现

  1. 新建一个BitmapUtils
 package cn.iaapp.app.sixman.util;

import android.graphics.Bitmap;
import android.widget.ImageView;

import com.youth.banner.Banner;

import java.util.ArrayList;
import java.util.List;

/**
 * 用来做三级缓存
 * Created by 梁 on 2018/6/1.
 */

public class BitmapUtils {

    private  NetCacheUtils netCacheUtils  ;  //网络下载
    private LocalUtils localUtils ;   //本地下载
    private final MemoryCacheUtils memoryCacheUtils;


    private  List<Bitmap> bitmapList = new ArrayList<>() ; //用于banner列表

    public BitmapUtils() {
        memoryCacheUtils = new MemoryCacheUtils();
        localUtils = new LocalUtils(memoryCacheUtils) ;
         netCacheUtils = new NetCacheUtils(localUtils,memoryCacheUtils);

    }

    /**
     * 用来三级缓存显示图片
     * @param imageView
     * @param url
     */
    public void  disPlay(ImageView imageView , String url)
    {

        //   1. 内存缓存 速度很快不浪费流量   优先
        Bitmap bitmapMemory = memoryCacheUtils.getMemoryCache(url);
        if (bitmapMemory != null)
        {
            imageView.setImageBitmap(bitmapMemory);
            return ;
        }
//        2.    本地缓存  速度快 不浪费流量    其次
        Bitmap bitmap = localUtils.getLocalCache(url);
        if (bitmap != null)
        {
            imageView.setImageBitmap(bitmap);
            return ;
        }
//        3.    网络缓存  速度慢浪费流量      最后
        netCacheUtils.getBitmapFromNet(imageView,url);

    }


    public void  disPlayBanner(Banner banner , List<String> urlList){

        //   1. 内存缓存 速度很快不浪费流量   优先

//        for (int i = 0 ; i < urlList.size() ; i ++)
//        {
//            Bitmap bitmap = memoryCacheUtils.getMemoryCache(urlList.get(i));
//            if (bitmap != null)
//            bitmapList.add(bitmap) ;
//        }
//        if (bitmapList .size() != 0)
//        {
//            banner.setImages(bitmapList);
//            return ;
//        }
//
        2.  本地缓存  速度快 不浪费流量    其次
//        for (int i = 0 ; i < urlList.size() ; i ++)
//        {
//            Bitmap bitmap = localUtils.getLocalCache(urlList.get(i));
//            if (bitmap != null)
//            bitmapList.add(bitmap) ;
//        }
//        if (bitmapList .size() != 0)
//        {
            banner.setImages(bitmapList);
//            return ;
//        }

//        3.    网络缓存  速度慢浪费流量      最后
        netCacheUtils.getBitmapListFromNet(banner , urlList);
    }





}
  1. 网络缓存
package cn.iaapp.app.sixman.util;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.widget.ImageView;

import com.youth.banner.Banner;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

/**
 * 网络缓存工具类
 * Created by 梁 on 2018/6/1.
 */

public class NetCacheUtils {

    private List <Bitmap> bitmapList = new ArrayList<>();

    private LocalUtils localUtils ;
    private MemoryCacheUtils memoryCacheUtils ;
    public NetCacheUtils(LocalUtils localUtils, MemoryCacheUtils memoryCacheUtils) {

        this.localUtils = localUtils ;
        this.memoryCacheUtils = memoryCacheUtils ;
    }

    public   void getBitmapFromNet(ImageView imageView , String url){
        //异步下载图片
        new BitmapTask().execute(imageView,url);
    }


    // 获取bitmap列表
    public void getBitmapListFromNet(Banner banner, final List<String> urlList) {


        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0 ; i < urlList.size() ; i ++)
                {

                    Bitmap bitmap = download(urlList.get(i));

                    //写本地缓存 和内存缓存
                    localUtils.setLocalCache(bitmap,urlList.get(i));
                    memoryCacheUtils.setMemoryCache(urlList.get(i),bitmap);
                    bitmapList.add(bitmap) ;
                }

            }
        }).start();

        banner.setImages(bitmapList) ;

    }













    class BitmapTask extends AsyncTask<Object,Void ,Bitmap>
    {


        private ImageView imageView;
        private String url;

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        @Override
        protected Bitmap doInBackground(Object... objects) {
            imageView = (ImageView) objects[0];
            url = (String) objects[1];
            imageView.setTag(url);  //与url 绑定一起
            //使用url 下载图片
            Bitmap bitmap = download(url);
            return bitmap;
        }


        @Override
        protected void onPostExecute(Bitmap result) {
            //给imagview  设置图片
            //由于Listview 的重用机制,导致某个item有可能展示重用的那个item的图片导致图片凑乱
            // 解决方案 确保当前设置的图片和当前显示的imageview 完全匹配

            String url  = (String) imageView.getTag();
            if (this.url .equals(url))
            { //判断当前下载的图片的url 和imageurl 是否一致
                if (result != null)
                    imageView.setImageBitmap(result);
                //写本地缓存
                localUtils.setLocalCache(result,url);
                memoryCacheUtils.setMemoryCache(url,result);
            }

        }
    }


    //使用url 下载图片
    private Bitmap download(String url) {
        HttpURLConnection conn = null;
        try {
              conn  = (HttpURLConnection) new URL(url).openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(5000);
            conn.connect();

            int responseCode = conn.getResponseCode();
            if (responseCode == 200)
            {
                InputStream inputStream = conn.getInputStream();
                Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                return bitmap ;
            }


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

        return  null ;
    }

}
  1. 本地缓存
package cn.iaapp.app.sixman.util;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.List;


/**
 * 本地缓存的工具类
 * Created by 梁 on 2018/6/1.
 */

public class LocalUtils {



    String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/jft_Cache/" ;   //缓存文件夹


    private  MemoryCacheUtils memoryCacheUtils ;
    public LocalUtils(MemoryCacheUtils memoryCacheUtils) {
        this.memoryCacheUtils = memoryCacheUtils ;
    }

    /**
     * 写缓存
     * @param bitmap  从网络下载得到的bitmap
     * @param url  图片的url 作为图片的唯一标识
     */
    public void  setLocalCache(Bitmap bitmap ,String url)     {
        //将图片保存到本地文件

        File dir = new File(path) ;
        if(!dir.exists() || !dir.isDirectory())
        {
            dir.mkdirs() ; // 创建文件夹
        }

        try {
            File cacheFile = new File(dir,MD5Util.md5String(url)+".JPEG") ;
            bitmap.compress(Bitmap.CompressFormat.JPEG,100,new FileOutputStream(cacheFile)) ;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

    }



    //读缓存
    public Bitmap  getLocalCache(String url){

        File cacheFile = new File(path,MD5Util.md5String(url) + ".JPEG");

        if (cacheFile.exists())
        {
             // 缓存路径
            try {
                Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(cacheFile));
                //写内存缓存
                memoryCacheUtils.setMemoryCache(url,bitmap);
                return bitmap ;
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }


        return null ;
    }



}

4.内存缓存

package cn.iaapp.app.sixman.util;

import android.graphics.Bitmap;
import android.support.v4.util.LruCache;

import java.lang.ref.SoftReference;
import java.util.HashMap;

/**
 * 内存缓存
 * Created by 梁 on 2018/6/1.
 */

public class MemoryCacheUtils {

    private HashMap<String , SoftReference<Bitmap>> mHashMap = new HashMap<>() ;

    private LruCache<String , Bitmap>  mLruCache;

    public MemoryCacheUtils( ) {

        //获取虚拟机分配的最大内存
        long maxMemory = Runtime.getRuntime().maxMemory();
        //maxSize :内存上限
        mLruCache = new LruCache<String,Bitmap>((int) (maxMemory / 8))
        {
            @Override // 用来返回单个对象占用内存的大小
            protected int sizeOf(String key, Bitmap value) {
                //计算图片占用内存的大小       //   int byteCount = value.getByteCount();
                int byteCount = value.getRowBytes() * value.getHeight();
                return byteCount;
            }
        }; //一般给 2M 也就是 1/8
    }

    //写缓存
    public  void setMemoryCache(String url , Bitmap bitmap){

//        SoftReference<Bitmap> bitmapSoftReference = new SoftReference<Bitmap>(bitmap); //用软引用包装
//        mHashMap.put(url,bitmapSoftReference) ;

        mLruCache.put(url,bitmap) ;
    }

    //读缓存
    public  Bitmap getMemoryCache(String url){

//        SoftReference<Bitmap> soft = mHashMap.get(url);
//        if (soft != null)
//        {
//            Bitmap bitmap = soft.get();  //从软引用中取出当前对象
//            return  bitmap;
//        }
        return mLruCache.get(url) ;

    }

}

使用

   BitmapUtils bitmapUtils = new BitmapUtils();
   bitmapUtils.disPlay(mIamgeView,url);

Glide 的内存缓存

Glide 是默认开启了内存缓存的,只要你通过 Glide 加载一张图片,他就会缓存到内存中,只要他还没被从内存中清理之前,下次使用 Glide 都会从内存缓存中加载。大大提升了图片加载的效率。

当然如果你有特殊要求,可以添加一行代码把默认开启的内存缓存关闭掉。
?
1
2
3
4

Glide.with(this)
.load(url)
.skipMemoryCache(true)//关闭内存缓存
.into(imageView);

Glide 的内存缓存实际上和我们上面说的差别不大,使用的也是LruCache算法,不过他还结合了一种弱引用机制,共同完成了内存缓存功能。

Glide 的硬盘缓存

关于 Glide 硬盘缓存使用也是十分简单。

       Glide.with(this)
                .load(url)
                .diskCacheStrategy(DiskCacheStrategy.RESULT)
                .into(imageView);

一个 diskCacheStrategy( ) 方法就可以调整他的硬盘缓存策略。其中可以传入的参数有四种:

 DiskCacheStrategy.NONE: 表示不缓存任何内容。
    DiskCacheStrategy.SOURCE: 表示只缓存原始图片。
    DiskCacheStrategy.RESULT: 表示只缓存转换过后的图片(默认选项)。
    DiskCacheStrategy.ALL : 表示既缓存原始图片,也缓存转换过后的图片。

Glide 的硬盘缓存是默认将图片压缩转换后再缓存到硬盘中,这种处理方式再避免OOM的时候会经常看见。

如果需要改变硬盘缓存策略只需要改变其传入的参数即可。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值