三级缓存简介
·内存缓存:优先加载,速度最快
·文件缓存:次之加载,速度次之
·网络缓存:最次加载,速度最慢,浪费流量
简单原理图
首先从内存缓存获取,其次再从文件缓存获取,最后从网络缓存获取。
从网络缓存获取后,同时保存到文件缓存和内存缓存,以便下次获取。
内存溢出OOM
android默认给每个app只分配16M的内存。
java中的引用
强引用 垃圾回收器不会回收,java默认引用都是强引用
软引用 SoftReference 在内存不够时,会考虑回收
弱引用 WeakReference 在内存不够时,会优先回收
虚引用 PhantomReference 在内存不够时,最优先回收
LruCache和DisLruCache两个类,分别用于内存和硬盘缓存。核心思想是当缓存空间满了之后,会删除最近最少使用的缓存。
内存缓存代码
LruCache
LruCache的原理是将缓存对象作为强引用,保存在LinkedHashMap中,当缓存满了之后,将对象从Map中移除,重新通过put方法添加新的缓存,get方法获取缓存。
LruCache的核心思想就是维护一个缓存对象的队列,该队列由LinkedHashMap维护。一直没访问的对象放在队尾,最新访问的放在队首,当队列满了之后,从队尾开始淘汰,队首的最后淘汰。
package com.seaicelin.bitmaputils;
import android.graphics.Bitmap;
import android.support.v4.util.LruCache;
public class MemoryCacheUtils {
private LruCache<String, Bitmap> mMemoryCache;
public MemoryCacheUtils() {
//最大内存的八分之一
long memoryMax = Runtime.getRuntime().maxMemory() / 8;
mMemoryCache = new LruCache<String, Bitmap>((int) memoryMax) {
@Override
protected int sizeOf(String key, Bitmap value) {
int byteCount = value.getRowBytes() * value.getHeight();
return byteCount;
}
};
}
/**
* 从内存读
*
* @param url
*/
public Bitmap getBitMapFromMemory(String url) {
return mMemoryCache.get(url);
}
/**
* 写内存
*
* @param url
* @param bitmap
*/
public void setBitmapToMemory(String url, Bitmap bitmap){
mMemoryCache.put(url, bitmap);
}
}
文件缓存代码
package com.seaicelin.bitmaputils;
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;
public class LocalCacheUtils {
private static final String CACHE= "/cache";
public static final String CACHE_PATH = Environment.getDownloadCacheDirectory().getAbsolutePath()
+ CACHE;
//从本地SD卡获取图片
public Bitmap getBitmapFromLocal(String url){
String fileName = Md5Encoder.encode(url);
File file = new File(CACHE_PATH, fileName);
if(file.exists()){
try {
Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(file));
return bitmap;
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
return null;
}
//向SD卡保存图片
public void setBitmapToLocal(String url, Bitmap bitmap){
String fileName = MD5Encoder.encode(url);
File file = new File(CACHE_PATH, fileName);
File parentFile = file.getParentFile();
if(!parentFile.exists()){//如果文件夹不存在,创建文件夹
parentFile.mkdirs();
}
//将图片保存在本地
try {
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, new FileOutputStream(file));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
网络缓存代码
package com.seaicelin.bitmaputils;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.widget.ImageView;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class NetCacheUtils {
private MemoryCacheUtils memoryCacheUtils;
private LocalCacheUtils localCacheUtils;
public NetCacheUtils(MemoryCacheUtils memoryCacheUtils, LocalCacheUtils localCacheUtils){
this.localCacheUtils = localCacheUtils;
this.memoryCacheUtils = memoryCacheUtils;
}
//从网络下载图片
public void getBitmapFromNet(ImageView imageView, String url){
new BitmapTask().execute(imageView, url);
}
private class BitmapTask extends AsyncTask<Object, Void, Bitmap> {
private ImageView image;
private String url;
@Override
protected Bitmap doInBackground(Object... params) {
image = (ImageView) params[0];
url = (String) params[1];
image.setTag(url);//must called from UI thread
return downloadBitmap(url);
}
@Override
protected void onPostExecute(Bitmap bitmap) {
if(bitmap != null){
String bindUrl = (String) image.getTag();
if(url.equals(bindUrl)){
image.setImageBitmap(bitmap);
setBitmapToLocalAndMemory(url, bitmap);
}
}
}
@Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
}
private Bitmap downloadBitmap(String url) {
HttpURLConnection conn = null;
try {
conn = (HttpURLConnection) new URL(url).openConnection();
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
conn.setRequestMethod("GET");
conn.connect();
int responseCode = conn.getResponseCode();
if(responseCode == 200){
InputStream in = conn.getInputStream();
//图片压缩处理
BitmapFactory.Options option= new BitmapFactory.Options();
option.inSampleSize = 2;//宽高压缩为原来的1/2,
option.inPreferredConfig = Bitmap.Config.RGB_565;//设置图片的格式
Bitmap bitmap = BitmapFactory.decodeStream(in, null, option);
return bitmap;
}
} catch (IOException e) {
e.printStackTrace();
} finally {
conn.disconnect();
}
return null;
}
//把下载好的图片保存到内存和本地
public void setBitmapToLocalAndMemory(String url, Bitmap bitmap){
memoryCacheUtils.setBitmapToMemory(url, bitmap);
localCacheUtils.setBitmapToLocal(url, bitmap);
}
}