参考:
Glide4用法官方文档:https://muyangmin.github.io/glide-docs-cn/doc/getting-started.html
Glide3.7.0源码解析:https://blog.csdn.net/sinyu890807/column/info/15318
《Android面试题:Glide》 https://blog.csdn.net/songzi1228/article/details/84426165
Q:了解Glide的实现原理吗?
A:了解过,主要有几个方面:
with方法是使用Glide加载图片的第一步,Glide类中的静态方法,返回RequestManager对象,根据传入的Context参数类型不同,主要有5个重载的with方法,区别是图片请求生命周期不同。
* @see #with(Context)
* @see #with(android.app.Activity)
* @see #with(android.app.Fragment)
* @see #with(androidx.fragment.app.Fragment)
* @see #with(androidx.fragment.app.FragmentActivity)
Glide可以根据当前页面的生命周期,自动重新开始或暂停或取消结束请求;实现原理就是根据传入的Context类型,在当前页面上生成一个看不见的fragment,来获得当前页面的生命周期的回调,进行请求相关的操作。如果传入的是Application,请求的生命周期将和应用一样长,不会自动取消;如果传入的是Activity或Fragment,当前Activity或Fragment退出时,请求将会自动终止。所以,从内存优化的角度看,应该传入当前页面的Context类型。比如child fragment页面上的Imagview显示图片,应该传入child fragment,而不是parent fragment和fragment所在的Activity。
可以看看源码的注释:
/**
* Begin a load with Glide by passing in a context.
*
* <p>Any requests started using a context will only have the application level options applied
* and will not be started or stopped based on lifecycle events. In general, loads should be
* started at the level the result will be used in. If the resource will be used in a view in a
* child fragment, the load should be started with {@link #with(android.app.Fragment)}} using that
* child fragment. Similarly, if the resource will be used in a view in the parent fragment, the
* load should be started with {@link #with(android.app.Fragment)} using the parent fragment. In
* the same vein, if the resource will be used in a view in an activity, the load should be
* started with {@link #with(android.app.Activity)}}.
*
* <p>This method is appropriate for resources that will be used outside of the normal fragment or
* activity lifecycle (For example in services, or for notification thumbnails).
*
* @param context Any context, will not be retained.
* @return A RequestManager for the top level application that can be used to start a load.
* @see #with(android.app.Activity)
* @see #with(android.app.Fragment)
* @see #with(androidx.fragment.app.Fragment)
* @see #with(androidx.fragment.app.FragmentActivity)
*/
@NonNull
public static RequestManager with(@NonNull Context context) {
return getRetriever(context).get(context);
}
所有with方法里面都是一句话,最终都是1.先调用getRetriever(context)方法获得RequestManagerRetriever对象,2.再调用RequestManagerRetriever对象的get(context)方法获得RequestManager对象。
RequestManagerRetriever这个类干嘛用的呢?源码里面的注释:A collection of static methods for creating new RequestManager or retrieving existing ones from activities and fragment.一些静态方法的集合,这些方法是用来创建新的requestManager对象或从activities和fragment中取回已存在的requestManager对象。
1.先看getRetriever(context)方法,
@NonNull
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
// Context could be null for other reasons (ie the user passes in null), but in practice it will
// only occur due to errors with the Fragment lifecycle.
Preconditions.checkNotNull(
context,
"You cannot start a load on a not yet attached View or a Fragment where getActivity() "
+ "returns null (which usually occurs when getActivity() is called before the Fragment "
+ "is attached or after the Fragment is destroyed).");
return Glide.get(context).getRequestManagerRetriever();
}
getRetriever(context)方法里面通过Glide.get(context)方法获取Glide单例对象,再调用getRequestManagerRetriever()简单的将requestManagerRetriever对象返回。在创建Glide单例对象的过程中,会创建并持有一个requestManagerRetriever对象。Glide单例对象在get方法里创建,这里先不跟进去看。(TODO:Glide的创建)
2.再看RequestManagerRetriever对象的get(context)方法,get方法和Glide里面的with方法一样有多个context子类参数的重载。
* @see #get(Context)
* @see #get(android.app.Activity)
* @see #get(android.app.Fragment)
* @see #get(androidx.fragment.app.Fragment)
* @see #get(androidx.fragment.app.FragmentActivity)
每个方法都看有点眼花,我们先看看其中的get(android.app.Activity)方法的实现
,(TODO:重载的get方法)
/**
* A collection of static methods for creating new {@link com.bumptech.glide.RequestManager}s or
* retrieving existing ones from activities and fragment.
*/
public class RequestManagerRetriever implements Handler.Callback {
......
public RequestManager get(@NonNull Activity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
return fragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
......
}
get(android.app.Activity)里面,先判断是否是后台线程,(如果是后台线程,请求无需根据activity页面的销毁而结束了),就直接调用参数ApplicationContext的get(Context)方法,创建一个和Application生命周期一样长的请求。如果是主线程,调用了fragmentGet方法并返回。
那么看看fragmenGet()方法:
private RequestManager fragmentGet(
@NonNull Context context,
@NonNull android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}
fragmenGet()方法里面,调用getRequestManagerFragment返回了一个fragment对象RequestManagerFragment,并创建一个RequestManager与fragment对象绑定,最后返回了RequestManager。
那么看看getRequestManagerFragment()方法:
private RequestManagerFragment getRequestManagerFragment(
@NonNull final android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingRequestManagerFragments.get(fm);
if (current == null) {
current = new RequestManagerFragment();
current.setParentFragmentHint(parentHint);
if (isParentVisible) {
current.getGlideLifecycle().onStart();
}
pendingRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
getRequestManagerFragment()方法里面,new RequestManagerFragment,并通过传入的FragmentManager添加到了页面上。从这里可以看出,RequestManagerFragment是根据页面的生命周期来管理Glide request请求的关键人物了。
那么看看RequestManagerFragment类里有什么,(可以源码的类的注释,一般都很清楚地描述了类的功能)
/**
* A view-less {@link android.app.Fragment} used to safely store an {@link
* com.bumptech.glide.RequestManager} that can be used to start, stop and manage Glide requests
* started for targets the fragment or activity this fragment is a child of.
*
* @see com.bumptech.glide.manager.SupportRequestManagerFragment
* @see com.bumptech.glide.manager.RequestManagerRetriever
* @see com.bumptech.glide.RequestManager
*/
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated
public class RequestManagerFragment extends Fragment {
......
private final ActivityFragmentLifecycle lifecycle;
private RequestManager requestManager;
public RequestManagerFragment() {
this(new ActivityFragmentLifecycle());
}
RequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
this.lifecycle = lifecycle;
}
public void setRequestManager(@Nullable RequestManager requestManager) {
this.requestManager = requestManager;
}
public RequestManager getRequestManager() {
return requestManager;
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
registerFragmentWithRoot(activity);
} catch (IllegalStateException e) {
// OnAttach can be called after the activity is destroyed, see #497.
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Unable to register fragment with root", e);
}
}
}
@Override
public void onDetach() {
super.onDetach();
unregisterFragmentWithRoot();
}
@Override
public void onStart() {
super.onStart();
lifecycle.onStart();
}
@Override
public void onStop() {
super.onStop();
lifecycle.onStop();
}
@Override
public void onDestroy() {
super.onDestroy();
lifecycle.onDestroy();
unregisterFragmentWithRoot();
}
private void registerFragmentWithRoot(@NonNull Activity activity) {
unregisterFragmentWithRoot();
rootRequestManagerFragment =
Glide.get(activity).getRequestManagerRetriever().getRequestManagerFragment(activity);
if (!equals(rootRequestManagerFragment)) {
rootRequestManagerFragment.addChildRequestManagerFragment(this);
}
}
private void unregisterFragmentWithRoot() {
if (rootRequestManagerFragment != null) {
rootRequestManagerFragment.removeChildRequestManagerFragment(this);
rootRequestManagerFragment = null;
}
}
......
}
RequestManagerFragment类继承Fragemt类,在onAttach,onDetach方法中分别调用了registerFragmentWithRoot,unregisterFragmentWithRoot实现子fragment的添加和移除。RequestManagerFragment的构造方法中new ActivityFragmentLifecycle对象,并且在onStart,onStop,onDestroy中分别调用了ActivityFragmentLifecycle对象的onStart,onStop,onDestroy方法,看来就是通过ActivityFragmentLifecycle保存和通知页面的生命周期状态的变化。
那么看看ActivityFragmentLifecycle类,
/**
* A {@link com.bumptech.glide.manager.Lifecycle} implementation for tracking and notifying
* listeners of {@link android.app.Fragment} and {@link android.app.Activity} lifecycle events.
*/
class ActivityFragmentLifecycle implements Lifecycle {
private final Set<LifecycleListener> lifecycleListeners =
Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>());
private boolean isStarted;
private boolean isDestroyed;
/**
* Adds the given listener to the list of listeners to be notified on each lifecycle event.
*
* <p>The latest lifecycle event will be called on the given listener synchronously in this
* method. If the activity or fragment is stopped, {@link LifecycleListener#onStop()}} will be
* called, and same for onStart and onDestroy.
*
* <p>Note - {@link com.bumptech.glide.manager.LifecycleListener}s that are added more than once
* will have their lifecycle methods called more than once. It is the caller's responsibility to
* avoid adding listeners multiple times.
*/
@Override
public void addListener(@NonNull LifecycleListener listener) {
lifecycleListeners.add(listener);
if (isDestroyed) {
listener.onDestroy();
} else if (isStarted) {
listener.onStart();
} else {
listener.onStop();
}
}
@Override
public void removeListener(@NonNull LifecycleListener listener) {
lifecycleListeners.remove(listener);
}
void onStart() {
isStarted = true;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStart();
}
}
void onStop() {
isStarted = false;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStop();
}
}
void onDestroy() {
isDestroyed = true;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onDestroy();
}
}
}
ActivityFragmentLifecycle类很简单,一个set集合接收注册监听,并在onStart,onStop,onDestroy方法中,通知所有注册监听类。
好了,with方法的跟踪就到此为止,总结下里面主要的几个事:
1.怎么创建Glide单例对象,
2.怎么实现对页面生命周期事件的响应(创建fragment到页面并与创建的requestManager绑定)。
通过上面的分析,我们知道with返回了一个RequestManager对象,现在看看RequestManager对象的load方法,
/**
* A class for managing and starting requests for Glide. Can use activity, fragment and connectivity
* lifecycle events to intelligently stop, start, and restart requests. Retrieve either by
* instantiating a new object, or to take advantage built in Activity and Fragment lifecycle
* handling, use the static Glide.load methods with your Fragment or Activity.
*
* @see Glide#with(android.app.Activity)
* @see Glide#with(androidx.fragment.app.FragmentActivity)
* @see Glide#with(android.app.Fragment)
* @see Glide#with(androidx.fragment.app.Fragment)
* @see Glide#with(Context)
*/
public class RequestManager
implements ComponentCallbacks2, LifecycleListener, ModelTypes<RequestBuilder<Drawable>> {
......
/**
* Equivalent to calling {@link #asDrawable()} and then {@link RequestBuilder#load(Bitmap)}.
*
* @return A new request builder for loading a {@link Drawable} using the given model.
*/
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable Bitmap bitmap) {
return asDrawable().load(bitmap);
}
/**
* Equivalent to calling {@link #asDrawable()} and then {@link RequestBuilder#load(Drawable)}.
*
* @return A new request builder for loading a {@link Drawable} using the given model.
*/
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable Drawable drawable) {
return asDrawable().load(drawable);
}
/**
* Equivalent to calling {@link #asDrawable()} and then {@link RequestBuilder#load(String)}.
*
* @return A new request builder for loading a {@link Drawable} using the given model.
*/
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
/**
* Equivalent to calling {@link #asDrawable()} and then {@link RequestBuilder#load(Uri)}.
*
* @return A new request builder for loading a {@link Drawable} using the given model.
*/
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable Uri uri) {
return asDrawable().load(uri);
}
/**
* Equivalent to calling {@link #asDrawable()} and then {@link RequestBuilder#load(File)}.
*
* @return A new request builder for loading a {@link Drawable} using the given model.
*/
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable File file) {
return asDrawable().load(file);
}
/**
* Equivalent to calling {@link #asDrawable()} and then {@link RequestBuilder#load(Integer)}.
*
* @return A new request builder for loading a {@link Drawable} using the given model.
*/
@SuppressWarnings("deprecation")
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
return asDrawable().load(resourceId);
}
/**
* Equivalent to calling {@link #asDrawable()} and then {@link RequestBuilder#load(URL)}.
*
* @return A new request builder for loading a {@link Drawable} using the given model.
*/
@SuppressWarnings("deprecation")
@CheckResult
@Override
@Deprecated
public RequestBuilder<Drawable> load(@Nullable URL url) {
return asDrawable().load(url);
}
/**
* Equivalent to calling {@link #asDrawable()} and then {@link RequestBuilder#load(byte[])}.
*
* @return A new request builder for loading a {@link Drawable} using the given model.
*/
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable byte[] model) {
return asDrawable().load(model);
}
/**
* A helper method equivalent to calling {@link #asDrawable()} and then {@link
* RequestBuilder#load(Object)} with the given model.
*
* @return A new request builder for loading a {@link Drawable} using the given model.
*/
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable Object model) {
return asDrawable().load(model);
}
}
从源码看出,load()方法的重载的方法真是多,接收不同的参数类型(Bitmap,Drawable,String,Uri,Integer等等),但里面都是一句话:1.先调用asDrawable方法返回RequestBuilder对象,2.再调用RequestBuilder对象的load方法,并将接收的参数直接传过去(说明load方法也是重载)。
1.那么看看asDrawable方法,(看方法注释,真是写的非常清楚)
/**
* Attempts to always load the resource using any registered {@link
* com.bumptech.glide.load.ResourceDecoder}s that can decode any subclass of {@link Drawable}.
*
* <p>By default, may return either a {@link android.graphics.drawable.BitmapDrawable} or {@link
* GifDrawable}, but if additional decoders are registered for other {@link Drawable} subclasses,
* any of those subclasses may also be returned.
*
* @return A new request builder for loading a {@link Drawable}.
*/
@NonNull
@CheckResult
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
asDrawable里面调用as方法,传入Drawable.class;记住这个Drawable.class,后面它将传递个RequestBuilder的泛型,代表资源类型。
看看as方法,(多看看注释)
/**
* Attempts to load the resource using any registered {@link
* com.bumptech.glide.load.ResourceDecoder}s that can decode the given resource class or any
* subclass of the given resource class.
*
* @param resourceClass The resource to decode.
* @return A new request builder for loading the given resource class.
*/
@NonNull
@CheckResult
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
as方法的注释:根据传入的资源类型返回一个request builder 去加载指定的资源类型。
前面传入的参数是Drawable.class,所以返回了RequestBuilder<Drawable>。
2.再调用RequestBuilder对象的load方法,那么看看RequestBuilder类的load方法,
RequestBuilder类的注释:一个泛型类,可以处理泛型资源类型的设置选项和启动负载。泛型为将要传递给Target的资源类型。
/**
* A generic class that can handle setting options and staring loads for generic resource types.
*
* @param <TranscodeType> The type of resource that will be delivered to the {@link
* com.bumptech.glide.request.target.Target}.
*/
// Public API.
@SuppressWarnings({"unused", "WeakerAccess"})
public class RequestBuilder<TranscodeType> extends BaseRequestOptions<RequestBuilder<TranscodeType>>
implements Cloneable, ModelTypes<RequestBuilder<TranscodeType>> {
......
/**
* Returns a request builder to load the given {@link java.lang.String}.
*
* <p>Note - this method caches data using only the given String as the cache key. If the data is
* a Uri outside of your control, or you otherwise expect the data represented by the given String
* to change without the String identifier changing, Consider using {@link
* com.bumptech.glide.request.RequestOptions#signature(com.bumptech.glide.load.Key)} to mixin a
* signature you create that identifies the data currently at the given String that will
* invalidate the cache if that data changes. Alternatively, using {@link
* com.bumptech.glide.load.engine.DiskCacheStrategy#NONE} and/or {@link
* com.bumptech.glide.request.RequestOptions#skipMemoryCache(boolean)} may be appropriate.
*
* @see #load(Object)
* @param string A file path, or a uri or url handled by {@link
* com.bumptech.glide.load.model.UriLoader}.
*/
@NonNull
@Override
@CheckResult
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}
@Override
public RequestBuilder<TranscodeType> load(@Nullable Bitmap bitmap) {
return loadGeneric(bitmap).apply(diskCacheStrategyOf(DiskCacheStrategy.NONE));
}
@Override
public RequestBuilder<TranscodeType> load(@Nullable Drawable drawable) {
return loadGeneric(drawable).apply(diskCacheStrategyOf(DiskCacheStrategy.NONE));
}
@Override
public RequestBuilder<TranscodeType> load(@Nullable Object model) {
return loadGeneric(model);
}
@Override
public RequestBuilder<TranscodeType> load(@Nullable Uri uri) {
return loadGeneric(uri);
}
@Override
public RequestBuilder<TranscodeType> load(@Nullable File file) {
return loadGeneric(file);
}
@Override
public RequestBuilder<TranscodeType> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
return loadGeneric(resourceId).apply(signatureOf(AndroidResourceSignature.obtain(context)));
}
@Override
public RequestBuilder<TranscodeType> load(@Nullable byte[] model) {
RequestBuilder<TranscodeType> result = loadGeneric(model);
if (!result.isDiskCacheStrategySet()) {
result = result.apply(diskCacheStrategyOf(DiskCacheStrategy.NONE));
}
if (!result.isSkipMemoryCacheSet()) {
result = result.apply(skipMemoryCacheOf(true /*skipMemoryCache*/));
}
return result;
}
@Nullable private Object model;
private boolean isModelSet;
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
......
}
load(String url)方法的注释:此方法仅使用给定字符串作为缓存键来缓存数据。如果数据是一个超出您控制范围的Uri,或者您期望由给定字符串表示的数据,若要在不更改字符串标识符的情况下进行更改,请考虑使用RequestOptions#signature(Key)来混合您创建的用于标识当前位于给定字符串处的数据的签名,如果数据更改,则使缓存无效。或者,使DiskCacheStrategy#NONE或RequestOptions.skipMemoryCache(boolean)可能是合适的。
简单地说就是,load方法接收的参数,会被作为缓存的key,当然我们也可以自定义key,使用RequestOptions#signature(Key)。(TODO:后面再说缓存的key)
我们看到所有的load方法,最后都是调用了下loadGeneric方法,并传入接收的参数。而loadGenric方法只有一个,参数类型为Object,方法里面用model存储了接收的参数,并返回RequestBuilder自身。那么也就是说,第三步into方法,也是在RequestBuilder类里了。
总结下第二步load方法做的事情:就一个,Object model成员变量存入load方法接收的不同类型参数。
(load方法基本啥也没干?有的怀疑是不是搞错了,去看了郭霖Glide3.7的源码解析,果然和4.12不一样,改版了)
直接看RequestBuilder的into方法,(还是可以先看看方法的注释)
/**
* Sets the {@link ImageView} the resource will be loaded into, cancels any existing loads into
* the view, and frees any resources Glide may have previously loaded into the view so they may be
* reused.
*
* @see RequestManager#clear(Target)
* @param view The view to cancel previous loads for and load the new resource into.
* @return The {@link com.bumptech.glide.request.target.Target} used to wrap the given {@link
* ImageView}.
*/
@NonNull
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread();
Preconditions.checkNotNull(view);
BaseRequestOptions<?> requestOptions = this;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
// Clone in this method so that if we use this RequestBuilder to load into a View and then
// into a different target, we don't retain the transformation applied based on the previous
// View's scale type.
switch (view.getScaleType()) {
case CENTER_CROP:
requestOptions = requestOptions.clone().optionalCenterCrop();
break;
case CENTER_INSIDE:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
requestOptions = requestOptions.clone().optionalFitCenter();
break;
case FIT_XY:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case CENTER:
case MATRIX:
default:
// Do nothing.
}
}
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions,
Executors.mainThreadExecutor());
}
第一行会判断是否在主线程,不是的话抛出异常,所以into方法必须在主线程调用。后面根据ImageView的ScaleType设置了requestionOptions,看样子是对图片做响应的缩放设置。
最后一句,干了两件事:1.将ImageView包装成Target,2.调用的另一个into方法。
下面分别看看:
1.将ImageView包装成Target
看看glideContext的buildImageViewTarget方法,
public <X> ViewTarget<ImageView, X> buildImageViewTarget(
@NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
继续跟进到imageViewTargetFactory.buildTarget(),
/**
* A factory responsible for producing the correct type of {@link
* com.bumptech.glide.request.target.Target} for a given {@link android.view.View} subclass.
*/
public class ImageViewTargetFactory {
@NonNull
@SuppressWarnings("unchecked")
public <Z> ViewTarget<ImageView, Z> buildTarget(
@NonNull ImageView view, @NonNull Class<Z> clazz) {
if (Bitmap.class.equals(clazz)) {
return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
} else if (Drawable.class.isAssignableFrom(clazz)) {
return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
} else {
throw new IllegalArgumentException(
"Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
}
}
}
工厂类ImageViewTargetFactory ,会根据第二个参数类型,也就是创建RequestBuilder时的泛型类型(代表资源类型),来决定将ImageView包装成BitmapImageViewTarget或者DrawableImageViewTarget。
BitmapImageViewTarget和DrawableImageViewTarget都是ImageViewTarget的子类,主要区别就一个方法不一样。
public class DrawableImageViewTarget extends ImageViewTarget<Drawable> {
......
@Override
protected void setResource(@Nullable Drawable resource) {
view.setImageDrawable(resource);
}
......
}
public class BitmapImageViewTarget extends ImageViewTarget<Bitmap> {
......
protected void setResource(Bitmap resource) {
view.setImageBitmap(resource);
}
......
}
那么看看关键的父类ImageViewTarget,这个类很简单
**
* A base {@link com.bumptech.glide.request.target.Target} for displaying resources in {@link
* android.widget.ImageView}s.
*
* @param <Z> The type of resource that this target will display in the wrapped {@link
* android.widget.ImageView}.
*/
public abstract class ImageViewTarget<Z> extends ViewTarget<ImageView, Z>
implements Transition.ViewAdapter {
@Nullable private Animatable animatable;
public ImageViewTarget(ImageView view) {
super(view);
}
/** @deprecated Use {@link #waitForLayout()} instead. */
@SuppressWarnings({"deprecation"})
@Deprecated
public ImageViewTarget(ImageView view, boolean waitForLayout) {
super(view, waitForLayout);
}
/**
* Returns the current {@link android.graphics.drawable.Drawable} being displayed in the view
* using {@link android.widget.ImageView#getDrawable()}.
*/
@Override
@Nullable
public Drawable getCurrentDrawable() {
return view.getDrawable();
}
/**
* Sets the given {@link android.graphics.drawable.Drawable} on the view using {@link
* android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable)}.
*
* @param drawable {@inheritDoc}
*/
@Override
public void setDrawable(Drawable drawable) {
view.setImageDrawable(drawable);
}
/**
* Sets the given {@link android.graphics.drawable.Drawable} on the view using {@link
* android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable)}.
*
* @param placeholder {@inheritDoc}
*/
@Override
public void onLoadStarted(@Nullable Drawable placeholder) {
super.onLoadStarted(placeholder);
setResourceInternal(null);
setDrawable(placeholder);
}
/**
* Sets the given {@link android.graphics.drawable.Drawable} on the view using {@link
* android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable)}.
*
* @param errorDrawable {@inheritDoc}
*/
@Override
public void onLoadFailed(@Nullable Drawable errorDrawable) {
super.onLoadFailed(errorDrawable);
setResourceInternal(null);
setDrawable(errorDrawable);
}
/**
* Sets the given {@link android.graphics.drawable.Drawable} on the view using {@link
* android.widget.ImageView#setImageDrawable(android.graphics.drawable.Drawable)}.
*
* @param placeholder {@inheritDoc}
*/
@Override
public void onLoadCleared(@Nullable Drawable placeholder) {
super.onLoadCleared(placeholder);
if (animatable != null) {
animatable.stop();
}
setResourceInternal(null);
setDrawable(placeholder);
}
@Override
public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
if (transition == null || !transition.transition(resource, this)) {
setResourceInternal(resource);
} else {
maybeUpdateAnimatable(resource);
}
}
@Override
public void onStart() {
if (animatable != null) {
animatable.start();
}
}
@Override
public void onStop() {
if (animatable != null) {
animatable.stop();
}
}
private void setResourceInternal(@Nullable Z resource) {
// Order matters here. Set the resource first to make sure that the Drawable has a valid and
// non-null Callback before starting it.
setResource(resource);
maybeUpdateAnimatable(resource);
}
private void maybeUpdateAnimatable(@Nullable Z resource) {
if (resource instanceof Animatable) {
animatable = (Animatable) resource;
animatable.start();
} else {
animatable = null;
}
}
protected abstract void setResource(@Nullable Z resource);
}
ImageViewTarget持有ImageView,所以给ImageView设置图片的方法都是在这里了:
简单看了看ImageViewTarget的父类ViewTarget,不贴代码了,得到一个关键信息:ViewTarget会持有request,通过ImageView的setTag方法存储对应的request对象。
2.调用的另一个into方法
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> options,
Executor callbackExecutor) {
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
Request request = buildRequest(target, targetListener, options, callbackExecutor);
Request previous = target.getRequest();
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
// If the request is completed, beginning again will ensure the result is re-delivered,
// triggering RequestListeners and Targets. If the request is failed, beginning again will
// restart the request, giving it another chance to complete. If the request is already
// running, we can let it continue running without interruption.
if (!Preconditions.checkNotNull(previous).isRunning()) {
// Use the previous request rather than the new one to allow for optimizations like skipping
// setting placeholders, tracking and un-tracking Targets, and obtaining View dimensions
// that are done in the individual Request.
previous.begin();
}
return target;
}
//给target设置request前,先清楚target之前得request和相关监听类
requestManager.clear(target);
//request和target绑定,也就是和ImageView绑定
target.setRequest(request);
//开始跟踪request
requestManager.track(target, request);
return target;
}
这里面创建了一个Request对象,如果target已经有request并且和当前创建的request相同的话,则使用旧的request开始请求。
这里我们关注倒数第二句, requestManager.track(target, request);
跟进看看 requestManager的track方法,
public class RequestManager
implements ComponentCallbacks2, LifecycleListener, ModelTypes<RequestBuilder<Drawable>> {
......
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
......
}
好,这里有出现两个Tracker类:
1.TargetTracker类:保存当前所有正在使用的target,并传递生命周期事件,控制target的start,stop,destroy等。
2.RequestTracker类:A class for tracking, canceling, and restarting in progress, completed, and failed requests.
TargetTracker类的track方法只是将target添加到set集合,下面我们看看RequestTracker类的runRequest方法:
public class RequestTracker {
......
/** Starts tracking the given request. */
public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
request.clear();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
}
pendingRequests.add(request);
}
}
......
}
好了,我们的request请求,就是在这里begin开始执行了,如果它不是暂停状态。
Request请求里面都是怎么执行的呢?点击进去发现,Request是个接口,那么需要回头看看创建request是什么了。
into方法里面的调用了buildRequest方法,buildRequest调用了buildRequestRecursive,看看buildRequestRecursive,
private Request buildRequestRecursive(
Object requestLock,
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
@Nullable RequestCoordinator parentCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
// Build the ErrorRequestCoordinator first if necessary so we can update parentCoordinator.
ErrorRequestCoordinator errorRequestCoordinator = null;
if (errorBuilder != null) {
errorRequestCoordinator = new ErrorRequestCoordinator(requestLock, parentCoordinator);
parentCoordinator = errorRequestCoordinator;
}
Request mainRequest =
buildThumbnailRequestRecursive(
requestLock,
target,
targetListener,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
requestOptions,
callbackExecutor);
if (errorRequestCoordinator == null) {
return mainRequest;
}
int errorOverrideWidth = errorBuilder.getOverrideWidth();
int errorOverrideHeight = errorBuilder.getOverrideHeight();
if (Util.isValidDimensions(overrideWidth, overrideHeight) && !errorBuilder.isValidOverride()) {
errorOverrideWidth = requestOptions.getOverrideWidth();
errorOverrideHeight = requestOptions.getOverrideHeight();
}
Request errorRequest =
errorBuilder.buildRequestRecursive(
requestLock,
target,
targetListener,
errorRequestCoordinator,
errorBuilder.transitionOptions,
errorBuilder.getPriority(),
errorOverrideWidth,
errorOverrideHeight,
errorBuilder,
callbackExecutor);
errorRequestCoordinator.setRequests(mainRequest, errorRequest);
return errorRequestCoordinator;
}
这里有三个关键对象,mainRquest,errorRequest,errorRequestCoordinator,猜测errorRequestCoordinator应该是协调mainRquest与errorRequest。这里我们先不看。(TODO:errorRequestCoordinator的实现原理)
先看看创建mainRequest的方法buildThumbnailRequestRecursive,
private Request buildThumbnailRequestRecursive(
Object requestLock,
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
@Nullable RequestCoordinator parentCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
if (thumbnailBuilder != null) {
// Recursive case: contains a potentially recursive thumbnail request builder.
if (isThumbnailBuilt) {
throw new IllegalStateException(
"You cannot use a request as both the main request and a "
+ "thumbnail, consider using clone() on the request(s) passed to thumbnail()");
}
TransitionOptions<?, ? super TranscodeType> thumbTransitionOptions =
thumbnailBuilder.transitionOptions;
// Apply our transition by default to thumbnail requests but avoid overriding custom options
// that may have been applied on the thumbnail request explicitly.
if (thumbnailBuilder.isDefaultTransitionOptionsSet) {
thumbTransitionOptions = transitionOptions;
}
Priority thumbPriority =
thumbnailBuilder.isPrioritySet()
? thumbnailBuilder.getPriority()
: getThumbnailPriority(priority);
int thumbOverrideWidth = thumbnailBuilder.getOverrideWidth();
int thumbOverrideHeight = thumbnailBuilder.getOverrideHeight();
if (Util.isValidDimensions(overrideWidth, overrideHeight)
&& !thumbnailBuilder.isValidOverride()) {
thumbOverrideWidth = requestOptions.getOverrideWidth();
thumbOverrideHeight = requestOptions.getOverrideHeight();
}
ThumbnailRequestCoordinator coordinator =
new ThumbnailRequestCoordinator(requestLock, parentCoordinator);
Request fullRequest =
obtainRequest(
requestLock,
target,
targetListener,
requestOptions,
coordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
isThumbnailBuilt = true;
// Recursively generate thumbnail requests.
Request thumbRequest =
thumbnailBuilder.buildRequestRecursive(
requestLock,
target,
targetListener,
coordinator,
thumbTransitionOptions,
thumbPriority,
thumbOverrideWidth,
thumbOverrideHeight,
thumbnailBuilder,
callbackExecutor);
isThumbnailBuilt = false;
coordinator.setRequests(fullRequest, thumbRequest);
return coordinator;
} else if (thumbSizeMultiplier != null) {
// Base case: thumbnail multiplier generates a thumbnail request, but cannot recurse.
ThumbnailRequestCoordinator coordinator =
new ThumbnailRequestCoordinator(requestLock, parentCoordinator);
Request fullRequest =
obtainRequest(
requestLock,
target,
targetListener,
requestOptions,
coordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
BaseRequestOptions<?> thumbnailOptions =
requestOptions.clone().sizeMultiplier(thumbSizeMultiplier);
Request thumbnailRequest =
obtainRequest(
requestLock,
target,
targetListener,
thumbnailOptions,
coordinator,
transitionOptions,
getThumbnailPriority(priority),
overrideWidth,
overrideHeight,
callbackExecutor);
coordinator.setRequests(fullRequest, thumbnailRequest);
return coordinator;
} else {
// Base case: no thumbnail.
return obtainRequest(
requestLock,
target,
targetListener,
requestOptions,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
}
}
和前面的方法有的像,这里也有个关键对象ThumbnailRequestCoordinator,应该是协调正常request与thumbRequest,这里我们仍然先忽略,(TODO:ThumbnailRequestCoordinator的实现原理)只看最后一句,也就是Base case: no thumbnail.
那么进入obtainRequest方法看看,
private Request obtainRequest(
Object requestLock,
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> requestOptions,
RequestCoordinator requestCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
Executor callbackExecutor) {
return SingleRequest.obtain(
context,
glideContext,
requestLock,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
glideContext.getEngine(),
transitionOptions.getTransitionFactory(),
callbackExecutor);
}
看到这里调用了SinglRequest的obtain方法获取单例对象,好了,找到了Request的具体实现类了SingleRequest,那么看看SingleRequest的begin方法,
@Override
public void begin() {
synchronized (requestLock) {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
if (model == null) {
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
width = overrideWidth;
height = overrideHeight;
}
// Only log at more verbose log levels if the user has set a fallback drawable, because
// fallback Drawables indicate the user expects null models occasionally.
int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
onLoadFailed(new GlideException("Received null model"), logLevel);
return;
}
if (status == Status.RUNNING) {
throw new IllegalArgumentException("Cannot restart a running request");
}
// If we're restarted after we're complete (usually via something like a notifyDataSetChanged
// that starts an identical request into the same Target or View), we can simply use the
// resource and size we retrieved the last time around and skip obtaining a new size, starting
// a new load etc. This does mean that users who want to restart a load because they expect
// that the view size has changed will need to explicitly clear the View or Target before
// starting the new load.
if (status == Status.COMPLETE) {
onResourceReady(resource, DataSource.MEMORY_CACHE);
return;
}
// Restarts for requests that are neither complete nor running can be treated as new requests
// and can run again from the beginning.
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
&& canNotifyStatusChanged()) {
target.onLoadStarted(getPlaceholderDrawable());
}
if (IS_VERBOSE_LOGGABLE) {
logV("finished run method in " + LogTime.getElapsedMillis(startTime));
}
}
}
粗略一看,我以为关键的一句是 倒数第二个if:target.onLoadStarted(getPlaceholderDrawable()); 在加载请求前给target设置占位图placeholder。那图片的请求在哪里???难道在前面计算size的方法里面?
倒数第三个if:先判断overWidth和overHeight是否是有效的(宽高都大于0或者等于图片的原始宽高),否则target.getSize方法中计算好width和height后,通过回调接口,还是调用了onSizeReady方法。
那么看看onSizeReady方法,
/** A callback method that should never be invoked directly. */
@Override
public void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
synchronized (requestLock) {
if (IS_VERBOSE_LOGGABLE) {
logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
if (status != Status.WAITING_FOR_SIZE) {
return;
}
status = Status.RUNNING;
float sizeMultiplier = requestOptions.getSizeMultiplier();
this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
if (IS_VERBOSE_LOGGABLE) {
logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
}
loadStatus =
engine.load(
glideContext,
model,
requestOptions.getSignature(),
this.width,
this.height,
requestOptions.getResourceClass(),
transcodeClass,
priority,
requestOptions.getDiskCacheStrategy(),
requestOptions.getTransformations(),
requestOptions.isTransformationRequired(),
requestOptions.isScaleOnlyOrNoTransform(),
requestOptions.getOptions(),
requestOptions.isMemoryCacheable(),
requestOptions.getUseUnlimitedSourceGeneratorsPool(),
requestOptions.getUseAnimationPool(),
requestOptions.getOnlyRetrieveFromCache(),
this,
callbackExecutor);
// This is a hack that's only useful for testing right now where loads complete synchronously
// even though under any executor running on any thread but the main thread, the load would
// have completed asynchronously.
if (status != Status.RUNNING) {
loadStatus = null;
}
if (IS_VERBOSE_LOGGABLE) {
logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
}
}
调用了engine的load方法,并传入了签名,宽高和各种requestOption配置(缓存,变化等),感觉很近网络加载了。
进入load方法,
load方法的注释,说明了请求的机制:一个资源会先从当前正在使用的资源中寻找,找到返回并将所有新的非正在使用资源移到内存缓存中,找不到去cache缓存中找,找到添加到当前正在使用的资源集合中并返回,没找到则先检查当前正在进行的加载请求有没有,有的话添加一个回调,没有的话开始一个新的加载请求。
/**
* Starts a load for the given arguments.
*
* <p>Must be called on the main thread.
*
* <p>The flow for any request is as follows:
*
* <ul>
* <li>Check the current set of actively used resources, return the active resource if present,
* and move any newly inactive resources into the memory cache.
* <li>Check the memory cache and provide the cached resource if present.
* <li>Check the current set of in progress loads and add the cb to the in progress load if one
* is present.
* <li>Start a new load.
* </ul>
*
* <p>Active resources are those that have been provided to at least one request and have not yet
* been released. Once all consumers of a resource have released that resource, the resource then
* goes to cache. If the resource is ever returned to a new consumer from cache, it is re-added to
* the active resources. If the resource is evicted from the cache, its resources are recycled and
* re-used if possible and the resource is discarded. There is no strict requirement that
* consumers release their resources so active resources are held weakly.
*
* @param width The target width in pixels of the desired resource.
* @param height The target height in pixels of the desired resource.
* @param cb The callback that will be called when the load completes.
*/
public <R> LoadStatus load(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
Class<?> resourceClass,
Class<R> transcodeClass,
Priority priority,
DiskCacheStrategy diskCacheStrategy,
Map<Class<?>, Transformation<?>> transformations,
boolean isTransformationRequired,
boolean isScaleOnlyOrNoTransform,
Options options,
boolean isMemoryCacheable,
boolean useUnlimitedSourceExecutorPool,
boolean useAnimationPool,
boolean onlyRetrieveFromCache,
ResourceCallback cb,
Executor callbackExecutor) {
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
EngineKey key =
keyFactory.buildKey(
model,
signature,
width,
height,
transformations,
resourceClass,
transcodeClass,
options);
EngineResource<?> memoryResource;
synchronized (this) {
memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
if (memoryResource == null) {
return waitForExistingOrStartNewJob(
glideContext,
model,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
options,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache,
cb,
callbackExecutor,
key,
startTime);
}
}
// Avoid calling back while holding the engine lock, doing so makes it easier for callers to
// deadlock.
cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE);
return null;
}
load方法里面,先生成EngineKey对象,拿着key,先去内存中找,找到回调出去,没找到则调用waitForExistingOrStartNewJob,顾名思义,等待一个已存在的请求或者开始一个新的请求。
继续看waitForExistingOrStartNewJob,
private <R> LoadStatus waitForExistingOrStartNewJob(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
Class<?> resourceClass,
Class<R> transcodeClass,
Priority priority,
DiskCacheStrategy diskCacheStrategy,
Map<Class<?>, Transformation<?>> transformations,
boolean isTransformationRequired,
boolean isScaleOnlyOrNoTransform,
Options options,
boolean isMemoryCacheable,
boolean useUnlimitedSourceExecutorPool,
boolean useAnimationPool,
boolean onlyRetrieveFromCache,
ResourceCallback cb,
Executor callbackExecutor,
EngineKey key,
long startTime) {
//从正在执行中的jobs查找是否已存在
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
//存在的话,给EngineJob添加回调
current.addCallback(cb, callbackExecutor);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
EngineJob<R> engineJob =
engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);
DecodeJob<R> decodeJob =
decodeJobFactory.build(
glideContext,
model,
key,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
onlyRetrieveFromCache,
options,
engineJob);
//存储当前的engineJob
jobs.put(key, engineJob);
//添加回调
engineJob.addCallback(cb, callbackExecutor);
//开始请求
engineJob.start(decodeJob);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
这里创建了EngineJob和DecodeJob,并调用了engineJob的start方法,开始执行decodeJob.
/**
* A class that manages a load by adding and removing callbacks for for the load and notifying
* callbacks when the load completes.
*/
class EngineJob<R> implements DecodeJob.Callback<R>, Poolable {
......
public synchronized void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor =
decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
executor.execute(decodeJob);
}
......
}
GlideExecutor线程池执行decodeJob,那么我们来看看decodeJob的run方法。
/**
* A class responsible for decoding resources either from cached data or from the original source
* and applying transformations and transcodes.
*
* <p>Note: this class has a natural ordering that is inconsistent with equals.
*
* @param <R> The type of resource that will be transcoded from the decoded and transformed
* resource.
*/
class DecodeJob<R>
implements DataFetcherGenerator.FetcherReadyCallback,
Runnable,
Comparable<DecodeJob<?>>,
Poolable {
......
public void run() {
GlideTrace.beginSectionFormat("DecodeJob#run(model=%s)", model);
DataFetcher<?> localFetcher = currentFetcher;
try {
if (isCancelled) {
notifyFailed();
return;
}
runWrapped();
} catch (CallbackException e) {
throw e;
} catch (Throwable t) {
if (stage != Stage.ENCODE) {
throwables.add(t);
notifyFailed();
}
if (!isCancelled) {
throw t;
}
throw t;
} finally {
if (localFetcher != null) {
localFetcher.cleanup();
}
GlideTrace.endSection();
}
}
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
stage = getNextStage(Stage.INITIALIZE);
currentGenerator = getNextGenerator();
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
private Stage getNextStage(Stage current) {
switch (current) {
case INITIALIZE:
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE
: getNextStage(Stage.RESOURCE_CACHE);
case RESOURCE_CACHE:
return diskCacheStrategy.decodeCachedData()
? Stage.DATA_CACHE
: getNextStage(Stage.DATA_CACHE);
case DATA_CACHE:
// Skip loading from source if the user opted to only retrieve the resource from cache.
return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
case SOURCE:
case FINISHED:
return Stage.FINISHED;
default:
throw new IllegalArgumentException("Unrecognized stage: " + current);
}
}
private DataFetcherGenerator getNextGenerator() {
switch (stage) {
case RESOURCE_CACHE:
return new ResourceCacheGenerator(decodeHelper, this);
case DATA_CACHE:
return new DataCacheGenerator(decodeHelper, this);
case SOURCE:
return new SourceGenerator(decodeHelper, this);
case FINISHED:
return null;
default:
throw new IllegalStateException("Unrecognized stage: " + stage);
}
}
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
while (!isCancelled
&& currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
if (stage == Stage.SOURCE) {
reschedule();
return;
}
}
// We've run out of stages and generators, give up.
if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
}
// Otherwise a generator started a new load and we expect to be called back in
// onDataFetcherReady.
}
......
}
run方法调用了runWrapped方法。runWrapped流程:
1.先调先调用了getNextStage(Stage.INITIALIZE)方法获取到当前的stage;
2.再调用getNextGenerator方法,getNextGenerator方法会根据stage获取到对应的DataFetcherGenerator对象(ResourceCacheGenerator/DataCacheGenerator/SourceGenerator);
3.最后调用runGenerators方法,里面执行了DataFetcherGenerator对象的startNext方法。startNext方法返回值如果是true就不会执行while语句块里面,否则获取下一个状态getNextStage,getNextGenerator, 如果stage == Stage.SOURCE调用reschedule重新执行job。
这里的关注点是第三步里面执行了DataFetcherGenerator对象的startNext方法,这里负责获取数据,从缓存或者网络上。
如果是从网络加载,会调用SourceGenerator对象的startNext方法:
/**
* Generates {@link com.bumptech.glide.load.data.DataFetcher DataFetchers} from original source data
* using registered {@link com.bumptech.glide.load.model.ModelLoader ModelLoaders} and the model
* provided for the load.
*
* <p>Depending on the disk cache strategy, source data may first be written to disk and then loaded
* from the cache file rather than returned directly.
*/
class SourceGenerator implements DataFetcherGenerator, DataFetcherGenerator.FetcherReadyCallback {
......
@Override
public boolean startNext() {
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
cacheData(data);
}
if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
sourceCacheGenerator = null;
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
loadData = helper.getLoadData().get(loadDataListIndex++);
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
startNextLoad(loadData);
}
}
return started;
}
private void startNextLoad(final LoadData<?> toStart) {
//这里的fetcher是HttpUrlFetcher,真正发起网络请求获取数据的类。
loadData.fetcher.loadData(
helper.getPriority(),
new DataCallback<Object>() {
@Override
public void onDataReady(@Nullable Object data) {
if (isCurrentRequest(toStart)) {
onDataReadyInternal(toStart, data);
}
}
@Override
public void onLoadFailed(@NonNull Exception e) {
if (isCurrentRequest(toStart)) {
onLoadFailedInternal(toStart, e);
}
}
});
}
......
}
先看看SourceGenerator类的注释:
*从原始源数据生成DataFetcher,使用注册的ModelLoader和为load提供model。
*<p>根据磁盘缓存策略,源数据可能首先写入磁盘,然后加载,而不是直接返回。
DaraFetcher是实际获取数据的类,ModelLoader是干嘛的?LoadData又是干嘛的?
1.ModelLoader的注释:
*一种工厂接口,用于将任意复杂的数据模型转换为具体的数据类型,DataFetcher使用该数据类型从model获取数据。
*<p>这不仅可以避免在xml和代码中重复维度以确定具有不同密度的设备上的视图大小,还允许您使用布局权重或以编程方式放置视图的维度,而不必强制获取通用资源大小。
*<p>获取的资源越小,使用的带宽和电池寿命就越短,每个资源的内存占用就越少。
*@param<Model>模型的类型。
*@param<Data>可以由{@link使用的数据类型
*com.bumptech.glide.load.resourcedodecoder}解码资源。
2.LoadData : ModelLoader的内部类,包含一组识别加载资源的Key、指向相同数据的备用缓存键和一个DataFetcher可用于获取缓存中未找到的数据。
3.model: 是我们调用load方法时,传入的参数。