最近在使用Glide,遇到不少不解的问题
- 生命周期是如何绑定的
- 缓存策略
从官方的例子开始
// 这里的this我们假设为Activity
Glide.with(this).load("http://goo.gl/gEgYUd").into(imageView);
with
// with返回了一个RequestManager,RequestManager将acitivity生命周期与request绑定
// https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/Glide.java#L668
public static RequestManager with(Activity activity) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(activity);
}
// https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/manager/RequestManagerRetriever.java#L120
public RequestManager get(Activity activity) {
if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
return fragmentGet(activity, fm);
}
}
// https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/manager/RequestManagerRetriever.java#L167
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
RequestManager fragmentGet(Context context, android.app.FragmentManager fm) {
RequestManagerFragment current = getRequestManagerFragment(fm);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
requestManager = new RequestManager(context,
current.getGlideLifecycle(), current.getRequestManagerTreeNode());
current.setRequestManager(requestManager);
}
return requestManager;
}
// https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/manager/RequestManagerRetriever.java#L152
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
RequestManagerFragment getRequestManagerFragment(final android.app.FragmentManager fm) {
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingRequestManagerFragments.get(fm);
if (current == null) {
// 这里生成了一个Fragment,通过重载其生命周期回调,就可以绑定activity的生命周期
current = new RequestManagerFragment();
pendingRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
// https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/manager/RequestManagerFragment.java
@Override
public void onStart() {
super.onStart();
lifecycle.onStart();
}
@Override
public void onStop() {
super.onStop();
lifecycle.onStop();
}
@Override
public void onDestroy() {
super.onDestroy();
lifecycle.onDestroy();
}
load
// 开始加载图片啦,首先生成了一个DrawableTypeRequest
// https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/RequestManager.java#L283
public DrawableTypeRequest<String> load(String string) {
return (DrawableTypeRequest<String>) fromString().load(string);
}
// https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/RequestManager.java#L303
public DrawableTypeRequest<String> fromString() {
return loadGeneric(String.class);
}
// https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/RequestManager.java#L624
private <T> DrawableTypeRequest<T> loadGeneric(Class<T> modelClass) {
ModelLoader<T, InputStream> streamModelLoader = Glide.buildStreamModelLoader(modelClass, context);
ModelLoader<T, ParcelFileDescriptor> fileDescriptorModelLoader =
Glide.buildFileDescriptorModelLoader(modelClass, context);
if (modelClass != null && streamModelLoader == null && fileDescriptorModelLoader == null) {
throw new IllegalArgumentException("Unknown type " + modelClass + ". You must provide a Model of a type for"
+ " which there is a registered ModelLoader, if you are using a custom model, you must first call"
+ " Glide#register with a ModelLoaderFactory for your custom model class");
}
return optionsApplier.apply(
new DrawableTypeRequest<T>(modelClass, streamModelLoader, fileDescriptorModelLoader, context,
glide, requestTracker, lifecycle, optionsApplier));
}
// https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/DrawableTypeRequest.java#L30
// DrawableTypeRequest继承自DrawableRequestBuilder,通过optionsApplier.apply可以调整加载参数
public class DrawableTypeRequest<ModelType> extends DrawableRequestBuilder<ModelType> implements DownloadOptions {...}
into
// https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/DrawableRequestBuilder.java#L456
// into正式开始加载图片,包括下载缓存显示
@Override
public Target<GlideDrawable> into(ImageView view) {
return super.into(view);
}
// https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/GenericRequestBuilder.java#L682
public Target<TranscodeType> into(ImageView view) {
Util.assertMainThread();
if (view == null) {
throw new IllegalArgumentException("You must pass in a non null View");
}
if (!isTransformationSet && view.getScaleType() != null) {
switch (view.getScaleType()) {
case CENTER_CROP:
applyCenterCrop();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
applyFitCenter();
break;
//$CASES-OMITTED$
default:
// Do nothing.
}
}
// 这里buildImageViewTarget返回了ImageViewTarget(确切来说是子类),封装了一个ImageView,在request结束后会设置对应的image
return into(glide.buildImageViewTarget(view, transcodeClass));
}
// https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/GenericRequestBuilder.java#L648
public <Y extends Target<TranscodeType>> Y into(Y target) {
Util.assertMainThread();
if (target == null) {
throw new IllegalArgumentException("You must pass in a non null Target");
}
if (!isModelSet) {
throw new IllegalArgumentException("You must first set a model (try #load())");
}
Request previous = target.getRequest();
if (previous != null) {
previous.clear();
requestTracker.removeRequest(previous);
previous.recycle();
}
// 这里的buildRequest最后会返回一个GenericRequest
// (代码很长,通过窥屏知道的http://blog.csdn.net/guolin_blog/article/details/53939176/)
Request request = buildRequest(target);
target.setRequest(request);
lifecycle.addListener(target);
requestTracker.runRequest(request);
return target;
}
// https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/manager/RequestTracker.java#L34
public void runRequest(Request request) {
requests.add(request);
if (!isPaused) {
// 请求从这里开始发起,搜索内存,磁盘缓存,及网络请求
request.begin();
} else {
pendingRequests.add(request);
}
}
// https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/request/GenericRequest.java#L261
@Override
public void begin() {
startTime = LogTime.getLogTime();
if (model == null) {
onException(null);
return;
}
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
// 真实的请求从这里开始,这个名字好坑
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
// 设置占位图
target.onLoadStarted(getPlaceholderDrawable());
}
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished run method in " + LogTime.getElapsedMillis(startTime));
}
}
// https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/request/GenericRequest.java#L425
@Override
public void onSizeReady(int width, int height) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
if (status != Status.WAITING_FOR_SIZE) {
return;
}
status = Status.RUNNING;
width = Math.round(sizeMultiplier * width);
height = Math.round(sizeMultiplier * height);
ModelLoader<A, T> modelLoader = loadProvider.getModelLoader();
final DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(model, width, height);
if (dataFetcher == null) {
onException(new Exception("Failed to load model: \'" + model + "\'"));
return;
}
ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
}
loadedFromMemoryCache = true;
// 这里进入engine的加载流程
loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
priority, isMemoryCacheable, diskCacheStrategy, this);
loadedFromMemoryCache = resource != null;
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
}
// https://github.com/bumptech/glide/blob/3.0/library/src/main/java/com/bumptech/glide/load/engine/Engine.java
// 简单看下,主要是查缓存及网络请求了
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();
final String id = fetcher.getId();
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) {
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;
}
EngineJob current = jobs.get(key);
if (current != null) {
current.addCallback(cb);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation,
transcoder, diskCacheProvider, diskCacheStrategy, priority);
EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(runnable);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}