公司做的框架使用的volley,这里做一下图片缓存的说明,实现储存图片,获取图片,清理单个图片缓存和清理全部图片缓存,但是在使用的过程中,发现清理了缓存,图片缓存依然存在,为什么呢,通过查看源码,发现,volley不仅有内存存储,还有sd卡存储,只是这个是封装起来的,需要自己去找到,并进行操作
使用步骤:
1.首先建立一个队列:
private RequestQueue mRequestQueue;
if (mRequestQueue == null) { mRequestQueue = Volley.newRequestQueue(context); }2.使用json作为参数做网络请求
3.将这个jsonObjectRequest()放进队列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; } };
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; } } }
蓝色字体显示,在new队列的时候,里面出现个缓存 DiskBasedCache(cacheDir)类,觉得自己找到了方向,进入这个类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); } }
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));这样,volley的所有缓存都得到了清理//同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();
但是在什么时候存的,怎么取得,我研究了这个文章,但是还是不够通透,http://blog.csdn.net/asdzheng/article/details/45955653 这个更详细http://www.w2bc.com/Article/20215 想要深入了解可以进去研究下,都是分析源码的