一、图片的三级缓存
1. 内存
1. 内存的引用
1. 强引用
特点:没有变量引用 ,就会被垃圾回收线程收到,直到程序崩溃,也不会回收
2. 软引用
特点:垃圾回收线程执行,不一定会回收,内存不足的时候,崩溃之前,清理软引用
3. 弱引用
特点:垃圾回收线程一跑,就被回收
4. 虚引用
特点:垃圾回收一跑也被清理,该应用获取的数据都为null
2. 针对android系统
1. LruCache
内存不足时,回收该容器中的数据
2. 本地(硬盘)
文件:
sdcard
app(/data/data/包名/cache)
sharedpreferences
3. 网络
网络读取
二、使用操作
1. 先从内存取
2. 再从本地文件中
3. 从网络取
三、加载网络图片错位
1. 标记
四、代码
public class BitmapCacheUtils
{
//动态获取jvm的内存
private int maxSize = (int) (Runtime.getRuntime().freeMemory() / 2);
//图片的缓存容器
private LruCache<String, Bitmap> memCache = new LruCache<String, Bitmap>(maxSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
// TODO Auto-generated method stub
return value.getRowBytes() * value.getHeight();
}
};
//保留最后一次访问url的信息
private Map<ImageView,String> urlImageViewDatas = new HashMap<ImageView, String>();
private File cacheDir ;
private MainActivity mainActivity;
private ExecutorService threadPool;
public BitmapCacheUtils(MainActivity mainActivity) {
this.mainActivity = mainActivity;
//获取当前app的cache目录
cacheDir = mainActivity.getCacheDir();
//线程池
threadPool = Executors.newFixedThreadPool(6);
}
public void display(ImageView iv, String ivUrl) {
<span style="color:#FF0000;"> // 1. 先从内存取</span>
Bitmap bitmap = memCache.get(ivUrl);
if (bitmap != null) {
System.out.println("从内存获取数据");
//缓存中有图片
iv.setImageBitmap(bitmap);
return;
}
<span style="color:#FF0000;"> // 2. 再从本地文件中, app(/data/data/包名/cache)</span>
bitmap = getCacheFile(ivUrl);
if (bitmap != null) {
System.out.println("从文件获取数据");
//本地文件中有图片
iv.setImageBitmap(bitmap);
return;
}
<span style="color:#FF0000;"> // 3. 从网络取</span>
urlImageViewDatas.put(iv, ivUrl);//保留最后一次访问的url
getBitmapFromNet(iv, ivUrl);
}
private void getBitmapFromNet(ImageView iv, String ivUrl) {
//new Thread(new DownLoadUrl(iv, ivUrl)).start();
//线程池
threadPool.submit(new DownLoadUrl(iv, ivUrl));
}
private class DownLoadUrl implements Runnable{
private String ivUrl;
private ImageView iv;
public DownLoadUrl(ImageView iv,String ivUrl){
this.iv = iv;
this.ivUrl = ivUrl;
}
@Override
public void run() {
//访问网络
try {
URL url = new URL(ivUrl);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setConnectTimeout(6000);//设置超时时间
con.setRequestMethod("GET");
int code = con.getResponseCode();
if (code == 200) {
//请求成功
InputStream inputStream = con.getInputStream();
final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
//1.往内存中添加
memCache.put(ivUrl, bitmap);
//2.往本地文件中添加
saveBitmapToCacheFile(bitmap,ivUrl);
//3.显示数据
mainActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
System.out.println("从网络获取数据");
// 显示图片
// 判断url是不是最新的
//是最新的 自己的数据
if (ivUrl.equals(urlImageViewDatas.get(iv))) {
//自己的数据
iv.setImageBitmap(bitmap);
}
}
});
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* 保存bitmap到cache目录的文件中
* @param bitmap
* @param ivUrl
*/
public void saveBitmapToCacheFile(Bitmap bitmap,String ivUrl) {
File file = new File(cacheDir,Md5Utils.md5(ivUrl));
try {
bitmap.compress(CompressFormat.JPEG, 100, new FileOutputStream(file));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* @param ivUrl
* 当做缓存图片的名字
* @return
*/
public Bitmap getCacheFile(String ivUrl){
//把ivUrl转换MD5值,再把md5 做文件名
File file = new File(cacheDir,Md5Utils.md5(ivUrl));
if (file != null && file.exists()) {
//文件存在
//把文件转换成bitmap
Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
//再往内存写
memCache.put(ivUrl, bitmap);
return bitmap;
} else {
//不存在
return null;
}
}
}
五、MD5工具类<pre name="code" class="java">public class Md5Utils {
/**
* @param path
* ?????·??
* @return
* ?????MD5?
*/
public static String getFileMD5(String path){
StringBuilder mess = new StringBuilder();
try {
FileInputStream fis = new FileInputStream(new File(path));
//???MD5??????
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] buffer = new byte[10240];
int len = fis.read(buffer);
while (len != -1) {
md.update(buffer, 0, len);
//??????
len = fis.read(buffer);
}
byte[] digest = md.digest();
for (byte b : digest){
//???????????16??????
int d = b & 0xff;// 0x000000ff
String hexString = Integer.toHexString(d);
if (hexString.length() == 1) {//?????4λ?0
hexString = "0" + hexString;
}
hexString = hexString.toUpperCase();
mess.append(hexString);//????????????2λ??????????????????
}
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return mess + "";
}
public static String md5(String str){
StringBuilder mess = new StringBuilder();
try {
//???MD5??????
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] bytes = str.getBytes();
byte[] digest = md.digest(bytes);
for (byte b : digest){
//???????????16??????
int d = b & 0xff;// 0x000000ff
String hexString = Integer.toHexString(d);
if (hexString.length() == 1) {//?????4λ?0
hexString = "0" + hexString;
}
mess.append(hexString);//????????????2λ??????????????????
}
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return mess + "";
}
}