关于图片的处理,必不可少要用到三级缓存技术。
什么是三级缓存?
三级缓存一般分为内存--文件--网络三级缓存
内存(手机内存):内存相对于磁盘缓存,速度会快很多,但是缺点就是容量较小,不能存储大容量数据,且容易被系统回收。LruCache
磁盘(SD卡):相对于内存来说存储空间很大,能够存储较多的数据。DiskLruCache(DiskLruCache是非Google官方编写,但获得官方认证的硬盘缓存类,该类没有限定在Android内,所以理论上Java应用也可以使用DiskLreCache来缓存。)
网络:服务器端,通过HTTP请求获得。
具体流程就是,同一张图片从网络获取一次,然后在本地缓存下来,之后加载同一张图片的时候就从缓存中去加载。
先在内存中查找,找到就进行加载,否则去磁盘查找,找到将图片添加到内存中,加载显示,否则从网络加载,并且缓存到内存和磁盘,并返回。这就是完整的三级缓存过程。
这里需要介绍的是内存缓存一共分为四类:强引用、软引用、弱引用和虚引用(后面我会再专门整理一篇博客的~)
到这里三级缓存应该大概明白了吧,下面是我写的实现demo
package simida.yz.com.imagecache.utils;
import android.app.Activity;
import android.app.DownloadManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.support.v4.util.LruCache;
import android.util.Log;
import android.widget.ImageView;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
/**
* Created by Administrator on 2016/12/2.
*/
public class LoadImageCache {
private Context mContext;
//网络地址
private String mImageUrl;
//磁盘存储文件名
private String mFileName;
//内存缓存
private LruCache<String, Bitmap> mLruCache;
//磁盘目录(sd卡的私有cache目录)
private String mFilePath;
public LoadImageCache(Context context, String url) {
this.mContext = context;
this.mImageUrl = url;
initLruCache();
initFileCache();
}
public void loadBitmap(final ImageView imageView) {
//现在内存中查找
Bitmap bitmap = mLruCache.get(mImageUrl);
if (bitmap != null) {
Log.i("tag", "thumbnail from LruCache ");
imageView.setImageBitmap(bitmap);
return;
} else {
//去磁盘查找
byte[] bytes = loadFromSD();
if (bytes != null) {
//保存缩略图到cache
saveThumbnailToLruCache(bytes, 500, 300);
bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
Log.i("tag", "bitmap from sdcard ");
imageView.setImageBitmap(bitmap);
return;
} else {
//网络加载 使用OKHTTP异步实现
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(mImageUrl).build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
byte[] fromNetWork = response.body().bytes();
//保存缩略图到cache
saveThumbnailToLruCache(fromNetWork, 500, 300);
//保存到sdcard
saveImageToSD(fromNetWork);
final Bitmap bitmap1 = BitmapFactory.decodeByteArray(fromNetWork, 0, fromNetWork.length);
Log.i("tag", "bitmap from network ");
((Activity)mContext).runOnUiThread(new Runnable() {
@Override
public void run() {
imageView.setImageBitmap(bitmap1);
}
});
}
});
}
}
}
//初始化磁盘缓存目录
private void initFileCache() {
//获取文件名称
mFileName = mImageUrl.substring(mImageUrl.lastIndexOf("/") + 1);
//判断sd卡是否挂载
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
//私有缓存目录
mFilePath = mContext.getExternalCacheDir().getAbsolutePath();
} else {
Log.i("tag", "sdcard is error! ");
}
}
//初始化内存缓存
private void initLruCache() {
if (mLruCache == null) {
//获取运行时内存总大小
long maxMemory = Runtime.getRuntime().maxMemory();
//一般设置图片缓存为手机内存的1/8
mLruCache = new LruCache<String, Bitmap>((int) (maxMemory / 8)) {
//用来衡量每张图片的大小,默认返回图片的数量
@Override
protected int sizeOf(String key, Bitmap value) {
//图片默认是ARGB_8888格式,每个像素占4个字节
// int values = value.getWidth() * value.getHeight() * 4;
int values = value.getRowBytes() * value.getHeight();
return values;
}
//结合软引用使用时,会配合这个方法,现在已经基本不用软引用,不用考虑
@Override
protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {
super.entryRemoved(evicted, key, oldValue, newValue);
}
};
}
}
//保存图片到磁盘
private void saveImageToSD(byte[] image) {
BufferedOutputStream bos = null;
try {
bos = new BufferedOutputStream(new FileOutputStream(new File(mFilePath, mFileName)));
bos.write(image, 0, image.length);
bos.flush();
bos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//关流
try {
if (bos != null) {
bos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
Log.i("tag", "bitmap to sdcard ");
}
//磁盘查找
private byte[] loadFromSD() {
FileInputStream fis = null;
BufferedInputStream bis = null;
//内存流
ByteArrayOutputStream baos = null;
try {
fis = new FileInputStream(new File(mFilePath, mFileName));
bis = new BufferedInputStream(fis);
baos = new ByteArrayOutputStream();
byte[] bys = new byte[1024 * 8];
int length = 0;
while ((length = bis.read(bys)) != -1) {
baos.write(bys, 0, length);
baos.flush();
}
byte[] bytes = baos.toByteArray();
return bytes;
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
//关流
try {
if (baos != null) {
baos.close();
}
if (bis != null) {
bis.close();
}
if (fis != null) {
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
Log.i("tag", "bitmap from sdcard ");
}
}
//保存图片的缩略图到内存缓存,(二次采样技术)
private void saveThumbnailToLruCache(byte[] image, int thumbWidth, int thumbHeight) {
BitmapFactory.Options options = new BitmapFactory.Options();
//只采图片的边界
options.inJustDecodeBounds = true;
//获取原图的高度和宽度
BitmapFactory.decodeByteArray(image, 0, image.length, options);
int width = options.outWidth;
int height = options.outHeight;
//计算缩略图宽高与原图宽高比例,取较大值作为最终缩放比例
int size0 = (int) (thumbWidth / (float) width);
int size1 = (int) (thumbHeight / (float) height);
int size = size0 > size1 ? size0 : size1;
options.inSampleSize = size;
//设置图片格式
options.inPreferredConfig = Bitmap.Config.RGB_565;
//采图片全部
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeByteArray(image, 0, image.length, options);
mLruCache.put(mImageUrl, bitmap);
Log.i("tag", "thumbnail to cache ");
}
}
Activity和布局文件都比较简单,布局中只有一个imageView,实例化上面个工具类,调用loadBitmap方法即可,这里就不贴出来了。
第一次打开时log信息:

关闭后打开log信息:

到这里三级缓存可以看明白了吧。
这只是三级缓存的简单实现,实际项目中,有许多优秀的第三方框架已经将缓存机制优化的非常棒了,有兴趣的朋友可以继续看我的博客,最近没有工作,想要好好整理一下以前的东西了~再不整理都忘记啦。。。
浙公网安备 33010602011771号