之前被人问及过,图片的三级缓存是什么啊,来给我讲讲,图片三级缓存,好高大尚的名字,听着挺厉害,应该是很厉害的技术,当时不会啊,也就没什么了,没有说出来呗,前一阶端用到了BitmapUtils的图片缓存框架,索性就自己找些知识点来研究一些图片的三级缓存是什么吧。真所谓是知识你要是不知道,那就真的说不出所以然来,但是当你真正的去了解了,三级缓存也不是那么高端的技术。好了,闲话不多说了,开始图片的三级缓存原理吧。
好了,既然知道了什么三级缓存的字面意思了,那么我们就来处理吧。
MemoryCacheUtils.Java:
package com.example.bitmaputils.bitmap;import android.graphics.Bitmap;import android.util.Log;import android.util.LruCache;/** * 内存缓存 */public class MemoryCacheUtils { /** * LinkedHashMap<>(10,0.75f,true); * <p/> * 10是最大致 0.75f是加载因子 true是访问排序 false插入排序 * * */ //private LinkedHashMap<String,Bitmap> mMemoryCache = new LinkedHashMap<>(5,0.75f,true); private LruCache<String, Bitmap> mLruCache; public MemoryCacheUtils() { long maxMemory = Runtime.getRuntime().maxMemory();//最大内存 默认是16兆 运行时候的 mLruCache = new LruCache<String, Bitmap>((int) (maxMemory / 8)) { @Override protected int sizeOf(String key, Bitmap value) { //int byteCount = value.getByteCount(); //得到图片字节数 // @return number of bytes between rows of the native bitmap pixels. int byteCount = value.getRowBytes() * value.getWidth(); return byteCount; } }; } /** * 从内存中读取 * * @param url */ public Bitmap getFromMemroy(String url) { Log.d("MyBitmapUtils", "从内存中加载图片"); return mLruCache.get(url); } /** * 写入到内存中 * * @param url * @param bitmap */ public void setToMemory(String url, Bitmap bitmap) { mLruCache.put(url, bitmap); }}
很简单吧,在这里我们使用了LruCache(),对图片进行了内存缓存,这里我们只是稍微进行了处理,在这里我们只是介绍原理,当然了哈,性能,OOM溢出问题我们在这里不作处理。
package com.example.bitmaputils.bitmap;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.os.Environment;import android.util.Log;import com.example.bitmaputils.MD5Encoder;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;/** * 本地缓存 */public class SDcardCacheUtils { /** * 我们读取内存的绝对路径 */ public static final String CACHE_PATH = Environment .getExternalStorageDirectory().getAbsolutePath() + "/aixuexi"; /** * 从本地读取 * @param url */ public Bitmap getFromSd(String url){ String fileName = null; try { //得到图片的url的md5的文件名 fileName = MD5Encoder.encode(url); } catch (Exception e) { e.printStackTrace(); } File file = new File(CACHE_PATH,fileName); //如果存在,就通过bitmap工厂,返回的bitmap,然后返回bitmap if (file.exists()){ try { Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(file)); Log.d("MyBitmapUtils", "从本地读取图片啊"); return bitmap; } catch (FileNotFoundException e) { e.printStackTrace(); } } return null; } /** * 向本地缓存 * * @param url 图片地址 * @param bitmap 图片 */ public void savaSd(String url,Bitmap bitmap){ String fileName = null; try { //我们对图片的地址进行MD5加密,作为文件名 fileName = MD5Encoder.encode(url); } catch (Exception e) { e.printStackTrace(); } /** * 以CACHE_PATH为文件夹 fileName为文件名 */ File file = new File(CACHE_PATH,fileName); //我们首先得到他的符文剑 File parentFile = file.getParentFile(); //查看是否存在,如果不存在就创建 if (!parentFile.exists()){ parentFile.mkdirs(); //创建文件夹 } try { //将图片保存到本地 /** * @param format The format of the compressed image 图片的保存格式 * @param quality Hint to the compressor, 0-100. 0 meaning compress for * small size, 100 meaning compress for max quality. Some * formats, like PNG which is lossless, will ignore the * quality setting * 图片的保存的质量 100最好 * @param stream The outputstream to write the compressed data. */ bitmap.compress(Bitmap.CompressFormat.JPEG,100,new FileOutputStream(file)); } catch (FileNotFoundException e) { e.printStackTrace(); } }}
NetCacheUtils .java:
package com.example.bitmaputils.bitmap;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.os.AsyncTask;import android.util.Log;import android.widget.ImageView;import java.io.IOException;import java.io.InputStream;import java.net.HttpURLConnection;import java.net.URL;/** * 网络缓存工具类 */public class NetCacheUtils { /** * 图片 */ private ImageView mImageView; /** * 图片地址 */ private String mUrl; /** * 本地缓存 */ private SDcardCacheUtils mDcardCacheUtils; /** * 内存缓存 */ private MemoryCacheUtils mMemoryCacheUtils; public NetCacheUtils(SDcardCacheUtils dcardCacheUtils, MemoryCacheUtils memoryCacheUtils) { mDcardCacheUtils = dcardCacheUtils; mMemoryCacheUtils = memoryCacheUtils; } /** * 从网络中下载图片 * * @param image * @param url */ public void getDataFromNet(ImageView image, String url) { new MyAsyncTask().execute(image, url); //启动Asynctask,传入的参数到对应doInBackground() } /** * 异步下载 * <p/> * 第一个泛型 : 参数类型 对应doInBackground() * 第二个泛型 : 更新进度 对应onProgressUpdate() * 第三个泛型 : 返回结果result 对应onPostExecute */ class MyAsyncTask extends AsyncTask<Object, Void, Bitmap> { /** * 后台下载 子线程 * * @param params * @return */ @Override protected Bitmap doInBackground(Object... params) { //拿到传入的image mImageView = (ImageView) params[0]; //得到图片的地址 mUrl = (String) params[1]; //将imageview和url绑定,防止错乱 mImageView.setTag(mUrl); Bitmap bitmap = downLoadBitmap(mUrl); return bitmap; } /** * 进度更新 UI线程 * * @param values */ @Override protected void onProgressUpdate(Void... values) { super.onProgressUpdate(values); } /** * 回调结果,耗时方法结束后,主线程 * * @param bitmap */ @Override protected void onPostExecute(Bitmap bitmap) { if (bitmap != null) { //得到图片的tag值 String url = (String) mImageView.getTag(); //确保图片设置给了正确的image if (url.equals(mUrl)) { mImageView.setImageBitmap(bitmap); /** * 当从网络上下载好之后保存到sdcard中 */ mDcardCacheUtils.savaSd(mUrl, bitmap); /** * 写入到内存中 */ mMemoryCacheUtils.setToMemory(mUrl, bitmap); Log.d("MyBitmapUtils", "我是从网络缓存中读取的图片啊"); } } } } /** * 下载图片 * * @param url 下载图片地址 * @return */ private Bitmap downLoadBitmap(String url) { //连接 HttpURLConnection conn = null; try { conn = (HttpURLConnection) new URL(url) .openConnection(); //设置读取超时 conn.setReadTimeout(5000); //设置请求方法 conn.setRequestMethod("GET"); //设置连接超时连接 conn.setConnectTimeout(5000); //连接 conn.connect(); //响应码 int code = conn.getResponseCode(); if (code == 200) { //请求正确的响应码是200 //得到响应流 InputStream inputStream = conn.getInputStream(); //得到bitmap对象 Bitmap bitmap = BitmapFactory.decodeStream(inputStream); return bitmap; } } catch (IOException e) { # e.printStackTrace(); } finally { conn.disconnect(); } return null; }}
好了,至此,一个简单的图片的三级缓存完成了,接下来看看使用吧。
MyBitmapUtils .java:
package com.example.bitmaputils.bitmap;/** * Created by 若兰 on 2016/1/29. * 一个懂得了编程乐趣的小白,希望自己 * 能够在这个道路上走的很远,也希望自己学习到的 * 知识可以帮助更多的人,分享就是学习的一种乐趣 * QQ:1069584784 * csdn:http://blog.csdn.net/wuyinlei */import android.graphics.Bitmap;import android.widget.ImageView;/** * 自定义的bitmap工具类 */public class MyBitmapUtils { /** * 网络缓存 */ public NetCacheUtils mNetCacheUtils; /** * 本地缓存 */ public SDcardCacheUtils mSdCacheUtils; /** * 内存缓存 */ public MemoryCacheUtils mMemoryCacheUtils; public MyBitmapUtils() { mSdCacheUtils = new SDcardCacheUtils(); mMemoryCacheUtils = new MemoryCacheUtils(); mNetCacheUtils = new NetCacheUtils(mSdCacheUtils, mMemoryCacheUtils); } /** * 展示图片的方法 * * @param image * @param url */ public void display(ImageView image, String url) { //从内存中读取 Bitmap fromMemroy = mMemoryCacheUtils.getFromMemroy(url); //如果内存中有的h话就直接返回,从内存中读取 if (fromMemroy != null) { image.setImageBitmap(fromMemroy); return; } //从本地SD卡读取 Bitmap fromSd = mSdCacheUtils.getFromSd(url); if (fromSd != null) { image.setImageBitmap(fromSd); mMemoryCacheUtils.setToMemory(url, fromSd); return; } //从网络中读取 mNetCacheUtils.getDataFromNet(image, url); }}
使用这个工具类就很简单了
只需在加载数据的适配器中
//声明图片加载工具类private MyBitmapUtils utils; public PhotoAdapter() { //mBitmapUtils = new BitmapUtils(MainActivity.this); // mBitmapUtils.configDefaultLoadingImage(R.mipmap.defaut); utils = new MyBitmapUtils(); }然后在getView()方法中,使用工具类中的display()方法就可以了。简单吧utils.display(holder.tvImage,mImageViews[position]);
在这里我们看下图片加载效果:
来看下LOGCAT日志:
01-29 11:19:48.127 5556-5556/com.example.bitmaputils D/MyBitmapUtils: 从本地读取图片啊01-29 11:19:48.395 5556-5556/com.example.bitmaputils D/MyBitmapUtils: 从本地读取图片啊01-29 11:19:48.687 5556-5556/com.example.bitmaputils D/MyBitmapUtils: 从本地读取图片啊01-29 11:19:49.282 5556-5556/com.example.bitmaputils D/MyBitmapUtils: 从内存中加载图片01-29 11:19:49.628 5556-5556/com.example.bitmaputils D/MyBitmapUtils: 从本地读取图片啊01-29 11:19:50.173 5556-5556/com.example.bitmaputils D/MyBitmapUtils: 我是从网络缓存中读取的图片啊01-29 11:19:58.630 5556-5556/com.example.bitmaputils D/MyBitmapUtils: 从内存中加载图片01-29 11:19:58.762 5556-5556/com.example.bitmaputils D/MyBitmapUtils: 从本地读取图片啊01-29 11:19:59.325 5556-5556/com.example.bitmaputils D/MyBitmapUtils: 我是从网络缓存中读取的图片啊01-29 11:19:59.624 5556-5556/com.example.bitmaputils D/MyBitmapUtils: 从本地读取图片啊01-29 11:56:40.897 15045-15045/com.example.bitmaputils D/MyBitmapUtils: 从本地读取图片啊01-29 11:56:40.923 15045-15045/com.example.bitmaputils D/MyBitmapUtils: 从内存中加载图片01-29 11:56:41.105 15045-15045/com.example.bitmaputils D/MyBitmapUtils: 从本地读取图片啊01-29 11:56:41.118 15045-15045/com.example.bitmaputils D/MyBitmapUtils: 从内存中加载图片01-29 11:56:41.268 15045-15045/com.example.bitmaputils D/MyBitmapUtils: 从本地读取图片啊01-29 11:56:41.283 15045-15045/com.example.bitmaputils D/MyBitmapUtils: 从内存中加载图片01-29 11:56:41.431 15045-15045/com.example.bitmaputils D/MyBitmapUtils: 从本地读取图片啊01-29 11:56:43.837 15045-15045/com.example.bitmaputils D/MyBitmapUtils: 从内存中加载图片01-29 11:56:44.013 15045-15045/com.example.bitmaputils D/MyBitmapUtils: 从本地读取图片啊01-29 11:56:46.047 15045-15045/com.example.bitmaputils D/MyBitmapUtils: 从内存中加载图片01-29 11:56:46.222 15045-15045/com.example.bitmaputils D/MyBitmapUtils: 从本地读取图片啊
好了,一个简单的图片三级缓存原理就这样的诞生了,当然正如开始所说,这里只是简单的原理介绍,像里面用到的AsyncTask异步加载,和LruCache在这里只是使用,在以后的篇章中会对这两个进行介绍的,好了,由于代码展示的代码量太多,这里我就不在上传怎么显示图片的源码了,下面我会提供github源码地址,可以找到我的这个demo的源码。如果有问题,或者独特的见解,咱们可以讨论哦,QQ:1069584784
联系客服