缓存key值:
在Engine的load()中:
public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher, ... // 获取图片的唯一标示,比如网络图片的url final String id = fetcher.getId(); // 构建一个缓存的key值,EngineKay对象 EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(), loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(), transcoder, loadProvider.getSourceEncoder()); // 获取图片的缓存 EngineResource<?> cached = loadFromCache(key, isMemoryCacheable); if (cached != null) { // 如果有缓存就直接调用GenericRequest的onResourceReady() cb.onResourceReady(cached); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Loaded resource from cache", startTime, key); } return null; } // 没有获取到图片的缓存 EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable); if (active != null) { cb.onResourceReady(active); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Loaded resource from active resources", startTime, key); } return null; } ... }缓存方式的选择:
public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher, ... // 获取图片的缓存1(使用LruCache算法) EngineResource<?> cached = loadFromCache(key, isMemoryCacheable); if (cached != null) { // 如果有缓存就直接调用GenericRequest的onResourceReady() cb.onResourceReady(cached); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Loaded resource from cache", startTime, key); } return null; } // 获取图片的缓存2(使用弱引用) EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable); if (active != null) { cb.onResourceReady(active); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Loaded resource from active resources", startTime, key); } return null; } ... }使用LruCache算法
private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) { // 这里的isMemoryCacheable就是skipMemoryCache中传入的boolean值 if (!isMemoryCacheable) { return null; } EngineResource<?> cached = getEngineResourceFromCache(key); if (cached != null) { cached.acquire(); // 将这个缓存图片添加到activeResorce集合中(这是一个弱引用的map),主要是为了保证正在使用中的图片不被LruCache算法回收掉 activeResources.put(key, new ResourceWeakReference(key, cached, getReferenceQueue())); } return cached; } @SuppressWarnings("unchecked") private EngineResource<?> getEngineResourceFromCache(Key key) { // 通过分析这里的cached就是构建Glide对象时创建的LruResourceCache,说明这里是用的是LruCache算法 // 这里就是等我们获取到缓存中的图片以后会将他从缓存中移除掉 Resource<?> cached = cache.remove(key); final EngineResource result; if (cached == null) { result = null; } else if (cached instanceof EngineResource) { // Save an object allocation if we've cached an EngineResource (the typical case). result = (EngineResource) cached; } else { result = new EngineResource(cached, true /*isCacheable*/); } return result; }使用弱引用
private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable) { if (!isMemoryCacheable) { return null; } EngineResource<?> active = null; // 从弱引用的集合中取值 WeakReference<EngineResource<?>> activeRef = activeResources.get(key); if (activeRef != null) { active = activeRef.get(); if (active != null) { active.acquire(); } else { activeResources.remove(key); } } return active; }内存缓存图片加载完成后的写入:1、写入到弱引用的缓存:
EngineJob中回到主线程的逻辑
@Override public void onResourceReady(final Resource<?> resource) { this.resource = resource; MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget(); } private static class MainThreadCallback implements Handler.Callback { @Override public boolean handleMessage(Message message) { if (MSG_COMPLETE == message.what || MSG_EXCEPTION == message.what) { EngineJob job = (EngineJob) message.obj; if (MSG_COMPLETE == message.what) { job.handleResultOnMainThread(); } else { job.handleExceptionOnMainThread(); } return true; } return false; } } private void handleResultOnMainThread() { if (isCancelled) { resource.recycle(); return; } else if (cbs.isEmpty()) { throw new IllegalStateException("Received a resource without any callbacks to notify"); } engineResource = engineResourceFactory.build(resource, isCacheable); hasResource = true; // Hold on to resource for duration of request so we don't recycle it in the middle of notifying if it // synchronously released by one of the callbacks. engineResource.acquire(); // 这里回调了Engine的onEngineJobComplete() listener.onEngineJobComplete(key, engineResource); for (ResourceCallback cb : cbs) { if (!isInIgnoredCallbacks(cb)) { engineResource.acquire(); cb.onResourceReady(engineResource); } } // Our request is complete, so we can release the resource. engineResource.release(); }Engine的onEngineJobComplete()
@SuppressWarnings("unchecked") @Override public void onEngineJobComplete(Key key, EngineResource<?> resource) { Util.assertMainThread(); // A null resource indicates that the load failed, usually due to an exception. if (resource != null) { resource.setResourceListener(key, this); if (resource.isCacheable()) { // 写入到弱引用的缓存 activeResources.put(key, new ResourceWeakReference(key, resource, getReferenceQueue())); } } // TODO: should this check that the engine job is still current? jobs.remove(key); }2、写入到LruCache的缓存: 同理来到 private void handleResultOnMainThread() { if (isCancelled) { resource.recycle(); return; } else if (cbs.isEmpty()) { throw new IllegalStateException("Received a resource without any callbacks to notify"); } engineResource = engineResourceFactory.build(resource, isCacheable); hasResource = true; // Hold on to resource for duration of request so we don't recycle it in the middle of notifying if it // synchronously released by one of the callbacks. // 记录图片被引入的次数:+1 engineResource.acquire(); // 这里回调了Engine的onEngineJobComplete()(写入弱引用缓存) listener.onEngineJobComplete(key, engineResource); for (ResourceCallback cb : cbs) { if (!isInIgnoredCallbacks(cb)) { engineResource.acquire(); cb.onResourceReady(engineResource); } } // Our request is complete, so we can release the resource. // 写入到LruCache的缓存 // 记录图片被引入的次数:-1 engineResource.release(); } void acquire() { if (isRecycled) { throw new IllegalStateException("Cannot acquire a recycled resource"); } if (!Looper.getMainLooper().equals(Looper.myLooper())) { throw new IllegalThreadStateException("Must call acquire on the main thread"); } ++acquired; } void release() { if (acquired <= 0) { 当acquired>0说明正在使用,图片放到了activeResource的弱引用当中 throw new IllegalStateException("Cannot release a recycled or not yet acquired resource"); } if (!Looper.getMainLooper().equals(Looper.myLooper())) { throw new IllegalThreadStateException("Must call release on the main thread"); } if (--acquired == 0) { // 当acquired=0的时候说明已经不再使用,调用此方法来释放资源 listener.onResourceReleased(key, this); } } @Override public void onResourceReleased(Key cacheKey, EngineResource resource) { Util.assertMainThread(); // 先从activeResources中移除 activeResources.remove(cacheKey); if (resource.isCacheable()) { // 在put到LruResourceCache中 cache.put(cacheKey, resource); } else { resourceRecycler.recycle(resource); } } 以上就可以得到:正在使用中的图片使用弱引用缓存,使用过后的用LruCache缓存在配置内存缓存的时候我们需要同时配置BitmapPool的大小,需要通过自定义的GlideModule来实现
public class MyMemoryCache implements GlideModule { @Override public void applyOptions(Context context, GlideBuilder builder) { builder.setMemoryCache(new LruResourceCache(1)); builder.setBitmapPool(new LruBitmapPool(1)); } @Override public void registerComponents(Context context, Glide glide) { } }一般情况下是不用我们去手动设置内存缓存的大小,这些Glide已经帮我们做好了:
Glide.with(this).setMemoryCategory(MemoryCategory.HIGH);MemoryCategory.HIGH(初始缓存的1.5倍)、MemoryCategory.NORMAL(初始大小的1倍)、MEmoryCategory.LOW(初始大小的0.5倍)
来到Glide生成key的地方
public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher, DataLoadProvider<T, Z> loadProvider, Transformation<Z> transformation, ResourceTranscoder<Z, R> transcoder, Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) { Util.assertMainThread(); long startTime = LogTime.getLogTime(); // 这里的fetcher其实就是HttpUrlFetcher final String id = fetcher.getId(); EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(), loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(), transcoder, loadProvider.getSourceEncoder()); }HttpUrlFetcher的getId()
@Override public String getId() { return glideUrl.getCacheKey(); } public String getCacheKey() { return stringUrl != null ? stringUrl : url.toString(); }发现id就是url(如果是string类型的就是本身,如果是Url对象就是url.toString())所以我们的解决办法就是创建一个MyGlideUrl继承自Glide的GlideUrl重写getCacheKey()
public class MyGlideUrl extends GlideUrl { private String mUrl; public MyGlideUrl(String url) { super(url); this.mUrl = url; } @Override public String getCacheKey() { return mUrl.replace(tokenParam(), ""); } private String tokenParam() { String param = ""; int tokonIndex = mUrl.indexOf("?token=") >= 0 ? mUrl.indexOf("?token=") : mUrl.indexOf("&token="); if (tokonIndex != -1) { int nextIndex = mUrl.indexOf("&", tokonIndex + 1); if (nextIndex != -1) { param = mUrl.substring(tokonIndex + 1, nextIndex + 1); } else { param = mUrl.substring(tokonIndex); } } return param; } }activity中引用:
Glide.with(this).load(new MyGlideUrl(url)).into(imageView);