公司做的框架使用的volley,这里做一下图片缓存的说明,实现储存图片,获取图片,清理单个图片缓存和清理全部图片缓存,但是在使用的过程中,发现清理了缓存,图片缓存依然存在,为什么呢,通过查看源码,发现,volley不仅有内存存储,还有sd卡存储,只是这个是封装起来的,需要自己去找到,并进行操作
使用步骤:
1.首先建立一个队列:
private RequestQueue mRequestQueue;
if (mRequestQueue == null) {
mRequestQueue = Volley.newRequestQueue(context);
}
2.使用json作为参数做网络请求
JsonObjectRequest jsonObjReq = new JsonObjectRequest(Request.Method.POST, url, jsonParams,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}
}) {
//添加请求头
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> headers = new HashMap<String, String>();
headers.put("Token", Token.getToken());
return headers;
}
};
3.将这个jsonObjectRequest()放进队列
mRequestQueue.add(jsonObjReq);
调用的时候,直接给jsonObject传对应的参数即可
这里需要加载图片的方法是:
1.首先建立一个内存类,去继承LruCache ,
public class BitMapCache implements ImageLoader.ImageCache {
private LruCache<String, Bitmap> cache;
private static BitMapCache bitMapCache;
private BitMapCache() {
int maxMemory = (int) Runtime.getRuntime().maxMemory();
cache = new LruCache<String, Bitmap>(8 * 1024 * 1024) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getRowBytes() * bitmap.getHeight();
}
};
}
public static BitMapCache getInstance() {
if (bitMapCache == null) {
bitMapCache = new BitMapCache();
}
return bitMapCache;
}
@Override
public Bitmap getBitmap(String url) {
return cache.get(url);
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
cache.put(url, bitmap);
}
public int getBitmapCacheSize() {
return cache.size();
}
public void removeBitmapSize() {
cache.evictAll();
}
public void clearBitmap(String url, int maxWidth, int maxHeight) {
cache.remove(getCacheKey(url, maxWidth, maxHeight));
}
//同ImageLoader里私有方法
private static String getCacheKey(String url, int maxWidth, int maxHeight) {
return (new StringBuilder(url.length() + 12)).append("#W").append(maxWidth).append("#H").append(maxHeight).append(url).toString();
}
这个缓存图片类里面实现了储存图片,获取图片,清理单个图片缓存和清理全部图片缓存,但是在使用的过程中,发现清理了缓存,图片缓存依然存在,为什么呢,通过查看源码,发现,volley不仅有内存存储,还有sd卡存储,只是这个是封装起来的,需要自己去找到,并进行操作
2.将内存缓存放进Imageloader,在实例化队列后,紧跟着实例化Imageloader,并设置了内存缓存大小
if (mImageLoader == null) {
mImageLoader = new ImageLoader(mRequestQueue, BitMapCache.getInstance());
}
3.实现将图片显示的方法
public void diaplayHeadImage(Context context, String url, final ImageView imageView, final int width, int height) {
ImageLoader.ImageListener listener = new ImageLoader.ImageListener() {
@Override
public void onResponse(ImageLoader.ImageContainer response, boolean isImmediate) {
if (response.getBitmap() != null) {
Bitmap bm = response.getBitmap();
if (width > 0) {
int bmWidth = bm.getWidth();
int bmHeight = bm.getHeight();
float scale = (float) width / bmWidth;
Matrix matrix = new Matrix();
matrix.postScale(scale, scale);
// 得到新的图片
bm = Bitmap.createBitmap(bm, 0, 0, bmWidth, bmHeight, matrix, true);
}
if (imageView.getTag() == null) {
imageView.setImageBitmap(bm);
} else if (response.getRequestUrl().contains(imageView.getTag().toString())) {
imageView.setImageBitmap(bm);
}
} else {
//set error image
imageView.setImageResource(R.mipmap.img_default);
}
}
@Override
public void onErrorResponse(VolleyError volleyError) {
//set error image
imageView.setImageResource(R.mipmap.img_default);
}
};
//有网再清理缓存
if (Utils.IsNetworkAvailble(context)) {
//清理图片缓存,内存缓存和磁盘缓存
BitMapCache.getInstance().clearBitmap(url, 0, 0);
mRequestQueue.getCache().remove(url);
// mRequestQueue.getCache().clear();
}
if (width != 0 || height != 0) {
//指定图片允许的最大宽度和高度
mImageLoader.get(url, listener, width, height);
} else {
mImageLoader.get(url, listener);
}
}
4.这里明显没有存储到内存卡的步骤,那么图片是什么存储到内存卡的,点击
mImageLoader.get进源码
public ImageLoader.ImageContainer get(String requestUrl, ImageLoader.ImageListener imageListener, int maxWidth, int maxHeight) {
this.throwIfNotOnMainThread();
final String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight);
Bitmap cachedBitmap = this.mCache.getBitmap(cacheKey);
ImageLoader.ImageContainer imageContainer;
if(cachedBitmap != null) {
imageContainer = new ImageLoader.ImageContainer(cachedBitmap, requestUrl, (String)null, (ImageLoader.ImageListener)null);
imageListener.onResponse(imageContainer, true);
return imageContainer;
} else {
imageContainer = new ImageLoader.ImageContainer((Bitmap)null, requestUrl, cacheKey, imageListener);
imageListener.onResponse(imageContainer, true);
ImageLoader.BatchedImageRequest request = (ImageLoader.BatchedImageRequest)this.mInFlightRequests.get(cacheKey);
if(request != null) {
request.addContainer(imageContainer);
return imageContainer;
} else {
ImageRequest newRequest = new ImageRequest(requestUrl, new Listener() {
public void onResponse(Bitmap response) {
ImageLoader.this.onGetImageSuccess(cacheKey, response);
}
}, maxWidth, maxHeight, Config.RGB_565, new ErrorListener() {
public void onErrorResponse(VolleyError error) {
ImageLoader.this.onGetImageError(cacheKey, error);
}
});
this.mRequestQueue.add(newRequest);
this.mInFlightRequests.put(cacheKey, new ImageLoader.BatchedImageRequest(newRequest, imageContainer));
return imageContainer;
}
}
}
没有找到,但是发现了即使
cachedBitmap==null和网络断开的情况下,仍然会有图片展示,所以查看这里肯定走了弯路,那就从开头再找,发现在 mRequestQueue = Volley.newRequestQueue(context);这里点进去 Volley类
public class Volley {
private static final String DEFAULT_CACHE_DIR = "volley";
public Volley() {
}
public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
File cacheDir = new File(context.getCacheDir(), "volley");
String userAgent = "volley/0";
try {
String network = context.getPackageName();
PackageInfo queue = context.getPackageManager().getPackageInfo(network, 0);
userAgent = network + "/" + queue.versionCode;
} catch (NameNotFoundException var6) {
;
}
if(stack == null) {
if(VERSION.SDK_INT >= 9) {
stack = new HurlStack();
} else {
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}
BasicNetwork network1 = new BasicNetwork((HttpStack)stack);
RequestQueue queue1 = new RequestQueue(new DiskBasedCache(cacheDir), network1);
queue1.start();
return queue1;
}
public static RequestQueue newRequestQueue(Context context) {
return newRequestQueue(context, (HttpStack)null);
}
}
蓝色字体显示,在new队列的时候,里面出现个缓存 DiskBasedCache(cacheDir)类,觉得自己找到了方向,进入这个类
public class DiskBasedCache implements Cache {
private final Map<String, DiskBasedCache.CacheHeader> mEntries;
private long mTotalSize;
private final File mRootDirectory;
private final int mMaxCacheSizeInBytes;
private static final int DEFAULT_DISK_USAGE_BYTES = 5242880;
private static final float HYSTERESIS_FACTOR = 0.9F;
private static final int CACHE_VERSION = 2;
public DiskBasedCache(File rootDirectory, int maxCacheSizeInBytes) {
this.mEntries = new LinkedHashMap(16, 0.75F, true);
this.mTotalSize = 0L;
this.mRootDirectory = rootDirectory;
this.mMaxCacheSizeInBytes = maxCacheSizeInBytes;
}
public DiskBasedCache(File rootDirectory) {
this(rootDirectory, 5242880);
}
public synchronized void clear() {
File[] files = this.mRootDirectory.listFiles();
if(files != null) {
File[] var5 = files;
int var4 = files.length;
for(int var3 = 0; var3 < var4; ++var3) {
File file = var5[var3];
file.delete();
}
}
this.mEntries.clear();
this.mTotalSize = 0L;
VolleyLog.d("Cache cleared.", new Object[0]);
}
public synchronized Entry get(String key) {
DiskBasedCache.CacheHeader entry = (DiskBasedCache.CacheHeader)this.mEntries.get(key);
if(entry == null) {
return null;
} else {
File file = this.getFileForKey(key);
DiskBasedCache.CountingInputStream cis = null;
try {
cis = new DiskBasedCache.CountingInputStream(new FileInputStream(file), (DiskBasedCache.CountingInputStream)null);
DiskBasedCache.CacheHeader.readHeader(cis);
byte[] e = streamToBytes(cis, (int)(file.length() - (long)cis.bytesRead));
Entry var7 = entry.toCacheEntry(e);
return var7;
} catch (IOException var15) {
VolleyLog.d("%s: %s", new Object[]{file.getAbsolutePath(), var15.toString()});
this.remove(key);
} finally {
if(cis != null) {
try {
cis.close();
} catch (IOException var14) {
return null;
}
}
}
return null;
}
}
public synchronized void initialize() {
if(!this.mRootDirectory.exists()) {
if(!this.mRootDirectory.mkdirs()) {
VolleyLog.e("Unable to create cache dir %s", new Object[]{this.mRootDirectory.getAbsolutePath()});
}
} else {
File[] files = this.mRootDirectory.listFiles();
if(files != null) {
File[] var5 = files;
int var4 = files.length;
for(int var3 = 0; var3 < var4; ++var3) {
File file = var5[var3];
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
DiskBasedCache.CacheHeader e = DiskBasedCache.CacheHeader.readHeader(fis);
e.size = file.length();
this.putEntry(e.key, e);
} catch (IOException var16) {
if(file != null) {
file.delete();
}
} finally {
try {
if(fis != null) {
fis.close();
}
} catch (IOException var15) {
;
}
}
}
}
}
}
public synchronized void invalidate(String key, boolean fullExpire) {
Entry entry = this.get(key);
if(entry != null) {
entry.softTtl = 0L;
if(fullExpire) {
entry.ttl = 0L;
}
this.put(key, entry);
}
}
public synchronized void put(String key, Entry entry) {
this.pruneIfNeeded(entry.data.length);
File file = this.getFileForKey(key);
try {
FileOutputStream deleted1 = new FileOutputStream(file);
DiskBasedCache.CacheHeader e = new DiskBasedCache.CacheHeader(key, entry);
e.writeHeader(deleted1);
deleted1.write(entry.data);
deleted1.close();
this.putEntry(key, e);
} catch (IOException var6) {
boolean deleted = file.delete();
if(!deleted) {
VolleyLog.d("Could not clean up file %s", new Object[]{file.getAbsolutePath()});
}
}
}
public synchronized void remove(String key) {
boolean deleted = this.getFileForKey(key).delete();
this.removeEntry(key);
if(!deleted) {
VolleyLog.d("Could not delete cache entry for key=%s, filename=%s", new Object[]{key, this.getFilenameForKey(key)});
}
}
private String getFilenameForKey(String key) {
int firstHalfLength = key.length() / 2;
String localFilename = String.valueOf(key.substring(0, firstHalfLength).hashCode());
localFilename = localFilename + String.valueOf(key.substring(firstHalfLength).hashCode());
return localFilename;
}
public File getFileForKey(String key) {
return new File(this.mRootDirectory, this.getFilenameForKey(key));
}
private void pruneIfNeeded(int neededSpace) {
if(this.mTotalSize + (long)neededSpace >= (long)this.mMaxCacheSizeInBytes) {
if(VolleyLog.DEBUG) {
VolleyLog.v("Pruning old cache entries.", new Object[0]);
}
long before = this.mTotalSize;
int prunedFiles = 0;
long startTime = SystemClock.elapsedRealtime();
Iterator iterator = this.mEntries.entrySet().iterator();
while(iterator.hasNext()) {
java.util.Map.Entry entry = (java.util.Map.Entry)iterator.next();
DiskBasedCache.CacheHeader e = (DiskBasedCache.CacheHeader)entry.getValue();
boolean deleted = this.getFileForKey(e.key).delete();
if(deleted) {
this.mTotalSize -= e.size;
} else {
VolleyLog.d("Could not delete cache entry for key=%s, filename=%s", new Object[]{e.key, this.getFilenameForKey(e.key)});
}
iterator.remove();
++prunedFiles;
if((float)(this.mTotalSize + (long)neededSpace) < (float)this.mMaxCacheSizeInBytes * 0.9F) {
break;
}
}
if(VolleyLog.DEBUG) {
VolleyLog.v("pruned %d files, %d bytes, %d ms", new Object[]{Integer.valueOf(prunedFiles), Long.valueOf(this.mTotalSize - before), Long.valueOf(SystemClock.elapsedRealtime() - startTime)});
}
}
}
private void putEntry(String key, DiskBasedCache.CacheHeader entry) {
if(!this.mEntries.containsKey(key)) {
this.mTotalSize += entry.size;
} else {
DiskBasedCache.CacheHeader oldEntry = (DiskBasedCache.CacheHeader)this.mEntries.get(key);
this.mTotalSize += entry.size - oldEntry.size;
}
this.mEntries.put(key, entry);
}
private void removeEntry(String key) {
DiskBasedCache.CacheHeader entry = (DiskBasedCache.CacheHeader)this.mEntries.get(key);
if(entry != null) {
this.mTotalSize -= entry.size;
this.mEntries.remove(key);
}
}
private static byte[] streamToBytes(InputStream in, int length) throws IOException {
byte[] bytes = new byte[length];
int count;
int pos;
for(pos = 0; pos < length && (count = in.read(bytes, pos, length - pos)) != -1; pos += count) {
;
}
if(pos != length) {
throw new IOException("Expected " + length + " bytes, read " + pos + " bytes");
} else {
return bytes;
}
}
private static class CacheHeader {
public long size;
public String key;
public String etag;
public long serverDate;
public long ttl;
public long softTtl;
public Map<String, String> responseHeaders;
private CacheHeader() {
}
public CacheHeader(String key, Entry entry) {
this.key = key;
this.size = (long)entry.data.length;
this.etag = entry.etag;
this.serverDate = entry.serverDate;
this.ttl = entry.ttl;
this.softTtl = entry.softTtl;
this.responseHeaders = entry.responseHeaders;
}
public static DiskBasedCache.CacheHeader readHeader(InputStream is) throws IOException {
DiskBasedCache.CacheHeader entry = new DiskBasedCache.CacheHeader();
ObjectInputStream ois = new ObjectInputStream(is);
byte version = ois.readByte();
if(version != 2) {
throw new IOException();
} else {
entry.key = ois.readUTF();
entry.etag = ois.readUTF();
if(entry.etag.equals("")) {
entry.etag = null;
}
entry.serverDate = ois.readLong();
entry.ttl = ois.readLong();
entry.softTtl = ois.readLong();
entry.responseHeaders = readStringStringMap(ois);
return entry;
}
}
public Entry toCacheEntry(byte[] data) {
Entry e = new Entry();
e.data = data;
e.etag = this.etag;
e.serverDate = this.serverDate;
e.ttl = this.ttl;
e.softTtl = this.softTtl;
e.responseHeaders = this.responseHeaders;
return e;
}
public boolean writeHeader(OutputStream os) {
try {
ObjectOutputStream e = new ObjectOutputStream(os);
e.writeByte(2);
e.writeUTF(this.key);
e.writeUTF(this.etag == null?"":this.etag);
e.writeLong(this.serverDate);
e.writeLong(this.ttl);
e.writeLong(this.softTtl);
writeStringStringMap(this.responseHeaders, e);
e.flush();
return true;
} catch (IOException var3) {
VolleyLog.d("%s", new Object[]{var3.toString()});
return false;
}
}
private static void writeStringStringMap(Map<String, String> map, ObjectOutputStream oos) throws IOException {
if(map != null) {
oos.writeInt(map.size());
Iterator var3 = map.entrySet().iterator();
while(var3.hasNext()) {
java.util.Map.Entry entry = (java.util.Map.Entry)var3.next();
oos.writeUTF((String)entry.getKey());
oos.writeUTF((String)entry.getValue());
}
} else {
oos.writeInt(0);
}
}
private static Map<String, String> readStringStringMap(ObjectInputStream ois) throws IOException {
int size = ois.readInt();
Object result = size == 0?Collections.emptyMap():new HashMap(size);
for(int i = 0; i < size; ++i) {
String key = ois.readUTF().intern();
String value = ois.readUTF().intern();
((Map)result).put(key, value);
}
return (Map)result;
}
}
private static class CountingInputStream extends FilterInputStream {
private int bytesRead;
private CountingInputStream(InputStream in) {
super(in);
this.bytesRead = 0;
}
public int read() throws IOException {
int result = super.read();
if(result != -1) {
++this.bytesRead;
}
return result;
}
public int read(byte[] buffer, int offset, int count) throws IOException {
int result = super.read(buffer, offset, count);
if(result != -1) {
this.bytesRead += result;
}
return result;
}
}
}
可以看到。在这个类里,写了各种存储和读取数据的方法,找到这里找到了方向,原来图片的读取和写入在一开始的时候就已经进行了。
5.找到了这个,但是是封装的,那么怎么去清理这个缓存呢,在new队列以后,我发现,使用队列对象,可以直接获取缓存的获取和删除
mRequestQueue.getCache().get(url) //获取单个缓存
mRequestQueue.getCache().remove(url); //清除单个缓存
mRequestQueue.getCache().clear(); //清除全部缓存
mRequestQueue.getCache().put(url,bitmap); //放入缓存
再加上清理内存缓存的方法
cache.remove(getCacheKey(url, maxWidth, maxHeight));
//同ImageLoader里私有方法
private static String getCacheKey(String url, int maxWidth, int maxHeight) {
return (new StringBuilder(url.length() + 12)).append("#W").append(maxWidth).append("#H").append(maxHeight).append(url).toString();
}
cache.evictAll();
这样,volley的所有缓存都得到了清理
但是在什么时候存的,怎么取得,我研究了这个文章,但是还是不够通透,http://blog.csdn.net/asdzheng/article/details/45955653 这个更详细http://www.w2bc.com/Article/20215 想要深入了解可以进去研究下,都是分析源码的