三级缓存图片
自己的第一篇小笔记,第一次完整的使用markdownpad进行文章的编辑,在某马学android也有快3个月了,一直都没有系统的总结自己说学过的知识点.所以这次下定决心用blog记录自己所学习的知识点,希望能激励自己,接下来也会将自己以前的知识点做个巩固,并做成笔记发到blog上,只有好好的巩固了知识点,以后才能找到满意的工作^ ^
三级缓存图片的概念
加载网络图片,比较耗时,因此每次去访问网络加载图片是非常消耗时间和流量的,因此对图片进行缓存是非常有必要的
三级缓存的优点
- 优先从内存中加载图片, 速度最快, 不浪费流量
- 其次从本地(sdcard)加载图片, 速度快, 不浪费流量
- 最后从网络下载图片, 速度慢, 浪费流量
三级缓存的流程
从内存中获取
从sd卡中获取(如果从内存中没有缓存的话)
如果从sd卡获取到了就保存一份到内存中
没有获取到就去网络获取
从网络去获取
- 网络获取到后,保存一份到内存中,保存一份到sd卡中,以便下次读取的时候,可以不用去请求网络获取
代码实现
将代码封装在一个方法中
LoadUtils.getImage(String url);
class LoadUtils { //LruCache是android v4包下提供的用来获取缓存的类,类似与一个map,有键值对 private Context mContext; private LruCache<String, Bitmap> lruCache; private ExecutorService newFixedThreadPool; public LoadUtils(Context context) { //[0.1]我们知道每个app运行的堆内存(VM heap)最大是16M,当然有的可以是32M,不过最多的还是16M //Runtime是java提供的类,因为是单例的,获取他的实例,要用getRuntime. int maxSize = (int)(Runtime.getRuntime().maxMemory()/8); //[0]在构造方法中初始化LruCache,形式参数是LruCache可以维护的最大内存,是个int值 lruCache = new LruCache<String, Bitmap>(maxSize) { //要重写里面的sizeOf()方法 @override protected int sizeOf(String key, Bitmap bitmap) { //在此处返回bitmap的大小,计数,为了不让lruCache内存溢出 //图片的大小就是图片的行像素*图片的高度 return bitmap.getRowBytes()*bitmap.getHeight(); } }; //创建线程池,用于网络访问下载图片的时候,这个方法其实就是new了一个线程池 newFixedThreadPool = Executors.newFixedThreadPool(5); this.mContext = context; } public Static Bitmap getImage(String url,RequestCallback callback) { //[1]先从内存中获取 Btimap bitmap = getImageFromCache(url); //判断bitmap是否为空 if(bitmap != null) { return bitmap; } //[2]bitmap等于空,从磁盘上获取 bitmap = getBitmapFromCacheFile(url); //判断获取的bitmap是否为空 if(bitmap != null) { return bitmap; } //[3]如果从sd卡获取还是为空,就从网络去获取bitmap getImageFromNet(url,callback); return null; } //[1]先从内存中获取 private Bitmap getImageFromCache(String url) { //用lruCache获去bitmap Bitmap bitmap = lruCache.get(url); return bitmap; } //[2]从磁盘上获取 private Bitmap getBitmapFromCacheFile(url) { try { //获去缓存文件夹,一般保存在磁盘的文件名称都与Md5加密过的 String fileName = MD5Encoder.encode(imageUrl); //2.图片放到哪个文件夹下去存储(sd卡,files文件夹,cache文件) File file = new File(mCtx.getCacheDir(), fileName); //判断文件是否存在 if(file == null || !file.exist()) { return null; } //3.从文件中获取图片 Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath()); //4.往内存中存储一份 lruCache.put(imageUrl, bitmap); return bitmap; } catch (Exception e) { e.printStackTrace(); } return null; } //[3]从网络获取图片 private void getImageFromNet(String url,RequestCallback callback) { //从网络获取图片,因为获取图片是网络获取的,所以要在子线程中进行,但是下载图片的时候开启一个子线程的话,会开启很多,因此就要开启使用线程池 newFixedThreadPool.exeucte(new RunnableTask(url,callback)); } class RunnableTask implements Runnable { String imageUrl; RequestCallback mCallback; public RunnableTask(String url,callback) { imageUrl = url; this.mCallback = callback; } //开始请求网络获取图片 @override public void run() { try { //将url封装一下 URL url = new URL(imageUrl); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setConnectTimeout(3000); connection.setReadTimeout(3000); //如果响应码是200,说明返回成功 if(connection.getResponseCode() == 200){ InputStream inputStream = connection.getInputStream(); //输入流转换成图片 Bitmap bitmap = BitmapFactory.decodeStream(inputStream); //网络获取图片后,需要在内存中存储一份 lruCache.put(imageUrl, bitmap); //文件中写入一份 saveToCache(bitmap); //因为还在子线程,所以要自己转到主线程中 ((XXActivity)mContext).runOnUiThread(new Runnable() { @Override public void run() { mCallback.downLoadFinished(bitmap); } }); return; } } catch (Exception e) { e.printStackTrace(); } } } //[4]从网络获取后,保存一份到本地文件中 //存储图片的方法 private void saveToCache(Bitmap bitmap){ try { String fileName = MD5Encoder.encode(imageUrl); //2.图片放到哪个文件夹下去存储(sd卡,files文件夹,cache文件) File file = new File(mContext.getCacheDir(), fileName); //3.往指定file写入数据 FileOutputStream fileOutputStream = new FileOutputStream(file.getAbsolutePath()); //4.写入文件 //参数一:存储图片的个数 //参数二:存储图片的质量,是否压缩 //参数三:输出流对象 bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream); } catch (Exception e) { e.printStackTrace(); } } }
以上就是初步的代码实现,还遗留一些小问题
因为从网络下载图片是异步的,因此我们并不能确定什么时候可以获取到图片,这是可以用回调,等图片下载完的时候回调下载好的图片,也可以用hander,用message的方式传递bitmap图像.
我们老师用的handler用来实现网上下载的图片的获取
回调就是声明一个接口
interface RequestCallback { void downLoadFinished(Bitmap bitmap); }