写在前面:
源码位置:https://github.com/bumptech/glide
本文中对应的版本为v4.9
源码阅读:
常用方式为:
Glide.with(fragment)
.load(myUrl)
.placeholder(placeholder)
.fitCenter()
.into(imageView);
那么便以此为切入点进行阅读,首先查看Glide的with方法。
/**
* Begin a load with Glide that will be tied to the given
* {@link android.support.v4.app.Fragment}'s lifecycle and that uses the given
* {@link android.support.v4.app.Fragment}'s default options.
*
* @param fragment The fragment to use.
* @return A RequestManager for the given Fragment that can be used to start a load.
*/
@NonNull
public static RequestManager with(@NonNull Fragment fragment) {
return getRetriever(fragment.getActivity()).get(fragment);
}
此方法返回一个RequestManager,用于加载图片。与之类似的方法还有几个,如:
@NonNull
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}
/**
* Begin a load with Glide by passing in a context.
*
* 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)}}.
*
* 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(android.support.v4.app.Fragment)
* @see #with(android.support.v4.app.FragmentActivity)
*/
@NonNull
public static RequestManager with(@NonNull Context context) {
return getRetriever(context).get(context);
}
其中,传入context的with方法注释有一大坨,大意是不同的参数类型对应不同的生命周期,尽量选择最合适的with方法来用。
那么RequestManager是什么呢,我们先进源码查看一下:
/**
* 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(android.support.v4.app.FragmentActivity)
* @see Glide#with(android.app.Fragment)
* @see Glide#with(android.support.v4.app.Fragment)
* @see Glide#with(Context)
*/
public class RequestManager implements LifecycleListener,
ModelTypes> {
......
注释的大意是,这个类负责管理Glide的请求,可以使用activity或者fragment等生命周期实现请求的开始、停止、重新开始等动作,可以通过以下方式获取,1,直接new一个对象,2.在activity或fragment的生命周期内使用Glide.with来获取。
再来看看getRetriever方法:
@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();
}
那么RequestManagerRetriver类是什么呢?
/**
* 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 {
......
注释大意是,这个类包含了一系列的用于创建RequestManager对象或获取一个已经存在的RequestManager对象的静态方法。那么Glide.get(context)做了什么呢?
/**
* Get the singleton.
*
* @return the singleton
*/
@NonNull
public static Glide get(@NonNull Context context) {
if (glide == null) {
synchronized (Glide.class) {
if (glide == null) {
checkAndInitializeGlide(context);
}
}
}
return glide;
}
get方法用来获取对象,创建对象时进行了初始化。
private static void checkAndInitializeGlide(@NonNull Context context) {
// In the thread running initGlide(), one or more classes may call Glide.get(context).
// Without this check, those calls could trigger infinite recursion.
if (isInitializing) {
throw new IllegalStateException("You cannot call Glide.get() in registerComponents(),"
+ " use the provided Glide instance instead");
}
isInitializing = true;
initializeGlide(context);
isInitializing = false;
}
那么 initializeGlide(context);做了什么呢,可以猜到初始化的逻辑在这个方法中。下面是这个方法的代码,可以看到还是挺长的。
@SuppressWarnings("deprecation")
private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
Context applicationContext = context.getApplicationContext();
GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules();
List manifestModules = Collections.emptyList();
if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
manifestModules = new ManifestParser(applicationContext).parse();
}
if (annotationGeneratedModule != null
&& !annotationGeneratedModule.getExcludedModuleClasses().isEmpty()) {
Set> excludedModuleClasses =
annotationGeneratedModule.getExcludedModuleClasses();
Iterator iterator = manifestModules.iterator();
while (iterator.hasNext()) {
com.bumptech.glide.module.GlideModule current = iterator.next();
if (!excludedModuleClasses.contains(current.getClass())) {
continue;
}
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "AppGlideModule excludes manifest GlideModule: " + current);
}
iterator.remove();
}
}
if (Log.isLoggable(TAG, Log.DEBUG)) {
for (com.bumptech.glide.module.GlideModule glideModule : manifestModules) {
Log.d(TAG, "Discovered GlideModule from manifest: " + glideModule.getClass());
}
}
RequestManagerRetriever.RequestManagerFactory factory =
annotationGeneratedModule != null
? annotationGeneratedModule.getRequestManagerFactory() : null;
builder.setRequestManagerFactory(factory);
for (com.bumptech.glide.module.GlideModule module : manifestModules) {
module.applyOptions(applicationContext, builder);
}
if (annotationGeneratedModule != null) {
annotationGeneratedModule.applyOptions(applicationContext, builder);
}
Glide glide = builder.build(applicationContext);
for (com.bumptech.glide.module.GlideModule module : manifestModules) {
module.registerComponents(applicationContext, glide, glide.registry);
}
if (annotationGeneratedModule != null) {
annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
}
applicationContext.registerComponentCallbacks(glide);
Glide.glide = glide;
}
首先,第4行 GeneratedAppGlideModule 不知道是什么,通过查阅资料后疑惑得到解答。Glide有自己的默认配置,但用户可以定制自己的配置,如何实现呢,
方式1:在Manifest中声明自定义类
方式2:使用注解
关于自定义配置,暂不讨论,先看initializeGlide的逻辑,主要做了以下几件事:
使用反射动态创建注解定义AppGildeModule的实现类或者反射动态创建Manifest定义的GlideModule的实现类
将AppGlideModule的实现类或者GlideModule的实现类中的Glide的配置信息设置到GlideBuilder中
使用GlideBuilder根据配置信息构建Glide对象
将AppGlideModule的实现类或者GlideModule的实现类的Glide组件注册到glide中
glide监听Application的组件生命周期
我们再看下 Glide glide = builder.build(applicationContext);内部具体做了什么:
@NonNull
Glide build(@NonNull Context context) {
if (sourceExecutor == null) {
// 设置执行网络请求的线程池
sourceExecutor = GlideExecutor.newSourceExecutor();
}
if (diskCacheExecutor == null) {
// 设置磁盘缓存线程池
diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
}
if (animationExecutor == null) {
// 设置动画线程池
animationExecutor = GlideExecutor.newAnimationExecutor();
}
if (memorySizeCalculator == null) {
// 这个类是用来计算内存缓存的一些数据的,如缓存大小
memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
}
if (connectivityMonitorFactory == null) {
// 用于创建监控网络的类(DefaultConnectivityMonitor或NullConnectivityMonitor)
// DefaultConnectivityMonitor实现了LifecycleListener接口,与Activity、fragment、application等生命周期有同步
// 通过监控网络的开关,提供在网络恢复时会重新执行请求的能力
connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
}
if (bitmapPool == null) {
int size = memorySizeCalculator.getBitmapPoolSize();
if (size > 0) {
bitmapPool = new LruBitmapPool(size);
} else {
bitmapPool = new BitmapPoolAdapter();
}
}
if (arrayPool == null) {
arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
}
if (memoryCache == null) {
memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
}
if (diskCacheFactory == null) {
// 磁盘缓存的工厂类,提供建立磁盘缓存的能力,关联类DiskLruCacheWrapper
diskCacheFactory = new InternalCacheDiskCacheFactory(context);
}
if (engine == null) {
// 创建engine,engine是非常重要的存在,主要管理请求,和缓存相关工作
engine =
new Engine(
memoryCache,
diskCacheFactory,
diskCacheExecutor,
sourceExecutor,
GlideExecutor.newUnlimitedSourceExecutor(),
GlideExecutor.newAnimationExecutor(),
isActiveResourceRetentionAllowed);
}
// 如果调用GlideBuilder的addGlobalRequestListener方法,将添加一个listener到defaultRequestListeners,以后每个请求都会回调到listener中
if (defaultRequestListeners == null) {
defaultRequestListeners = Collections.emptyList();
} else {
defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners);// 这个小细节挺有趣的,作用是返回一个不可以修改的list
}
RequestManagerRetriever requestManagerRetriever =
new RequestManagerRetriever(requestManagerFactory);
return new Glide(
context,
engine,
memoryCache,
bitmapPool,
arrayPool,
requestManagerRetriever,
connectivityMonitorFactory,
logLevel,
defaultRequestOptions.lock(),
defaultTransitionOptions,
defaultRequestListeners,
isLoggingRequestOriginsEnabled);
}
上面对创建了Glide实例,但是engine内部我们还没有分析,暂时搁置,继续回到Glide.with方法,我们查看了getRetriever(context).get(context);方法的前半部分,后半部分,即get方法做了什么呢。
@SuppressWarnings("deprecation")
@NonNull
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方法的入参即with方法的入参,也是有几种类型(Activity/context/fragment…)。不论哪个方法,当检测到是backGroundThread的时候,执行了get方法:
@NonNull
public RequestManager get(@NonNull Context context) {
if (context == null) {
throw new IllegalArgumentException("You cannot start a load on a null Context");
} else if (Util.isOnMainThread() && !(context instanceof Application)) {
if (context instanceof FragmentActivity) {
return get((FragmentActivity) context);
} else if (context instanceof Activity) {
return get((Activity) context);
} else if (context instanceof ContextWrapper) {
return get(((ContextWrapper) context).getBaseContext());
}
}
return getApplicationManager(context);
}
如果是Application的context,则返回getApplicationManager(context);如果不是Application的context,最终通过递归的操作也会返回getApplicationManager(context);
@NonNull
private RequestManager getApplicationManager(@NonNull Context context) {
// Either an application context or we're on a background thread.
if (applicationManager == null) {
synchronized (this) {
if (applicationManager == null) {
// Normally pause/resume is taken care of by the fragment we add to the fragment or
// activity. However, in this case since the manager attached to the application will not
// receive lifecycle events, we must force the manager to start resumed using
// ApplicationLifecycle.
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context.getApplicationContext());
applicationManager =
factory.build(
glide,
new ApplicationLifecycle(),
new EmptyRequestManagerTreeNode(),
context.getApplicationContext());
}
}
}
return applicationManager;
}
可以此时返回的requestManager是个单例。如果不是子线程呢,会执行get方法后面的xxxGet方法,如:
@SuppressWarnings({"deprecation", "DeprecatedIsStillUsed"})
@Deprecated
@NonNull
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;
}
这个方法里面创建了RequestManager,先看getRequestManagerFragment:
@SuppressWarnings("deprecation")
@NonNull
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;
}
这个方法创建(复用)了一个fragment,这是一个特殊的fragment:
/**
* 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
*/
其是一个空的fragment,主要用于监听生命周期,其内部有RequestManager变量和lifeCycle变量。回到fragmentGet方法,获取到feagment后,获取fragment的RequestManager,如果为空则新建一个RequestManager。
到此为止,已经获取到了RequestManager,Glide.with方法告一段落。
Glide.with(fragment)
.load(myUrl)
.placeholder(placeholder)
.fitCenter()
.into(imageView);
下面看下load方法:
/**
* 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 load(@Nullable String string) {
return asDrawable().load(string);
}
load方法有很多重载版本,但第一部分,都是执行了asDrawable方法。其根据不同的类型(一般是Drawable)返回一个RequestBuilder,其负责构建Request相关动作。再看第二部分的load方法,在RequestBuilder内部:
public RequestBuilder load(@Nullable String string) {
return loadGeneric(string);
}
@NonNull
private RequestBuilder loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
到此为止没有发起请求,只是初始化一些变量。再看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 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());
}
前半部分重新构建requestOptions,不需要点进去看,大概知道是跟填充模式有关的构建,直接看后半部分的逻辑,即into方法,传入的参数有几个,分别是target、requestOptions、线程池。
@NonNull
@Synthetic
> Y into(
@NonNull Y target,
@Nullable RequestListener targetListener,
Executor callbackExecutor) {
return into(target, targetListener, /*options=*/ this, callbackExecutor);
}
private > Y into(
@NonNull Y target,
@Nullable RequestListener targetListener,
BaseRequestOptions> options,
Executor callbackExecutor) {
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
// 构建Request
Request request = buildRequest(target, targetListener, options, callbackExecutor);
// 判断重复请求
Request previous = target.getRequest();
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
request.recycle();
// 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;
}
requestManager.clear(target);
target.setRequest(request);
// 进入请求的流程
requestManager.track(target, request);
return target;
}
查看下 requestManager.track(target, request):
synchronized void track(@NonNull Target> target, @NonNull Request request) {
targetTracker.track(target); // 存储active状态的target
requestTracker.runRequest(request); // 发起请求
}
/**
* Starts tracking the given request.
*/
public void runRequest(@NonNull Request request) {
requests.add(request); // 存储request
if (!isPaused) {
request.begin();
} else {
request.clear();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
}
pendingRequests.add(request); // 存储request
}
}
两处存储request的地方,有什么区别呢?分别看下注释:
// Most requests will be for views and will therefore be held strongly (and safely) by the view
// via the tag. However, a user can always pass in a different type of target which may end up not
// being strongly referenced even though the user still would like the request to finish. Weak
// references are therefore only really functional in this context for view targets. Despite the
// side affects, WeakReferences are still essentially required. A user can always make repeated
// requests into targets other than views, or use an activity manager in a fragment pager where
// holding strong references would steadily leak bitmaps and/or views.
private final Set requests =
Collections.newSetFromMap(new WeakHashMap());
// A set of requests that have not completed and are queued to be run again. We use this list to
// maintain hard references to these requests to ensure that they are not garbage collected
// before they start running or while they are paused. See #346.
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
private final List pendingRequests = new ArrayList<>();
requests:不是很理解注释的意思.
pendingRequests:一个未结束的request放入队列中,以便将来开始请求,强引用的作用是在这个request暂停时或者未开始时避免其被gc掉。
接下来看下request是如何开始的,前面request.begain()这行作为切入点:
有几个实现类,那么此处具体是哪个实现类呢?我们回到RequestBuilder.into方法查看:
Request request = buildRequest(target, targetListener, options, callbackExecutor);
再进入buildRequest方法:
private Request buildRequest(......) {
return buildRequestRecursive(
......);
}
private Request buildRequestRecursive(
......) {
// Build the ErrorRequestCoordinator first if necessary so we can update parentCoordinator.
ErrorRequestCoordinator errorRequestCoordinator = null;
if (errorBuilder != null) {
errorRequestCoordinator = new ErrorRequestCoordinator(parentCoordinator);
parentCoordinator = errorRequestCoordinator;
}
Request mainRequest =
buildThumbnailRequestRecursive(
......);
......
Request errorRequest =
errorBuilder.buildRequestRecursive(
......);
errorRequestCoordinator.setRequests(mainRequest, errorRequest);
return errorRequestCoordinator;
}
private Request buildThumbnailRequestRecursive(
......) {
if (thumbnailBuilder != null) {
......
ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
Request fullRequest =
obtainRequest(
......);
isThumbnailBuilt = true;
// Recursively generate thumbnail requests.
Request thumbRequest =
thumbnailBuilder.buildRequestRecursive(
......);
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(parentCoordinator);
Request fullRequest =
obtainRequest(
......);
BaseRequestOptions> thumbnailOptions =
requestOptions.clone().sizeMultiplier(thumbSizeMultiplier);
Request thumbnailRequest =
obtainRequest(
......);
coordinator.setRequests(fullRequest, thumbnailRequest);
return coordinator;
} else {
// Base case: no thumbnail.
return obtainRequest(
......);
}
}
可以发现所有的request都是通过obtainRequest来创建的:
private Request obtainRequest(
Target target,
RequestListener targetListener,
BaseRequestOptions> requestOptions,
RequestCoordinator requestCoordinator,
TransitionOptions, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
Executor callbackExecutor) {
return SingleRequest.obtain(
context,
glideContext,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
glideContext.getEngine(),
transitionOptions.getTransitionFactory(),
callbackExecutor);
}
所以,至此疑惑得到解决,request是通过SingleRequest类获取的,而SingleRequest类的obtain方法,尝试从对象池中取出对象,如果对象为空,则创建一个新的对象。找到具体实现类后,就可以继续查看其begin方法了。
@Override
public synchronized void begin() {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime(); // 记录开始时间
if (model == null) { // mode是load方法传进来的参数,如url string
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));
}
}
1.先判断是不是传进来的参数如url是空的,如果是非法的,进入失败状态;
2.再判断是不是正在请求中,如果是,抛出异常;
3.再判断是不是请求完成了,如果是则调用onResourceReady,最终回调到UI部分;
4.再判断是不是size已经合法了,如果是就执行onSizeReady(关于overrideWidth&overrideHeight的设置请参见下面的示例代码)
5.再判断是是不是可以回调onLoadStarted设置placeHolder
示例代码:
RequestOptions options = new RequestOptions()
.placeholder(R.mipmap.ic_launcher)//加载成功之前占位图
.error(R.mipmap.ic_launcher)//加载错误之后的错误图
.override(400,400)//指定图片的尺寸
.fitCenter() //指定图片的缩放类型为fitCenter (等比例缩放图片,宽或者是高等于ImageView的宽或者是高。)
.centerCrop()//指定图片的缩放类型为centerCrop (等比例缩放图片,直到图片的狂高都大于等于ImageView的宽度,然后截取中间的显示。)
.circleCrop()//指定图片的缩放类型为centerCrop (圆形)
.skipMemoryCache(true)//跳过内存缓存
.diskCacheStrategy(DiskCacheStrategy.ALL)//缓存所有版本的图像
.diskCacheStrategy(DiskCacheStrategy.NONE)//跳过磁盘缓存
.diskCacheStrategy(DiskCacheStrategy.DATA)//只缓存原来分辨率的图片
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)//只缓存最终的图片 ;
Glide.with(this).load(url).apply(options).into(img);
看到这里,依然不知道request是怎么执行请求动作的,再回头看看begin方法,发现onSizeReady方法有玄机:
/**
* A callback method that should never be invoked directly.
*/
@Override
public synchronized void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
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方法是关键。首先,传了很多的参数到load方法中,这些参数我们之前都没有距离了解过来源和意义。先来了解下:
我们继续看engine.load方法执行了什么,这个方法很长,一步一步分析:
/**
* Starts a load for the given arguments.
*
* Must be called on the main thread.
*
*
The flow for any request is as follows:
*
*
* - Check the current set of actively used resources, return the active resource if present,
* and move any newly inactive resources into the memory cache.
*
- Check the memory cache and provide the cached resource if present.
*
- Check the current set of in progress loads and add the cb to the in progress load if one
* is present.
*
- Start a new load.
*
*
* 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 synchronized LoadStatus load(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
Class> resourceClass,
Class transcodeClass,
Priority priority,
DiskCacheStrategy diskCacheStrategy,
Map, 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;
// 创建key,用来做什么?(EngineKey:An in memory only cache key used to multiplex loads.)
// 从类的注释上来看,是用来做缓存的key的
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);
// 此处是从尝试根据上面生成的key从ActiveResources中取出资源,ActiveResources类维护了一个map,key是EngineKey,value是ReourceWeakReference
// 从名字来看,是当前激活状态下的资源缓存,即有一个request请求到了资源,但是还没释放,就存在这个ActiveResource中,算是一种轻量级临时内存缓存。
EngineResource> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return null;
}
// 如果ActiveResources中没有本次请求所对应的资源,就尝试从MemoryCache中获取
// 如果内存缓存中存在资源,则返回,并put到ActiveResources的map中
EngineResource> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return null;
}
// 如果内存缓存中不存在资源,则从jobs中根据key获取一个EngineJob
// 如果job不是空,则执行EngineJob的addCallback方法传入callbackExecutor,这个callbackExecutor是从何处传来的呢,可以回溯到RequestBuilde的into方法
// 如果不指定的话,默认传的是Executors.mainThreadExecutor(),其实就是一个主线程的handler机制,将任务post到主线程中执行
// private static final Executor MAIN_THREAD_EXECUTOR =
// new Executor() {
// private final Handler handler = new Handler(Looper.getMainLooper());
//
// @Override
// public void execute(@NonNull Runnable command) {
// handler.post(command);
// }
// };
// 那么这个EngineJob取出来干什么呢,为什么要从这里取出来呢,我们先看看从哪里put到jobs中的
// 是在本方法后面的jobs.put(key, engineJob);这一行,且只有此处调用了put。
// 所以这是一种避免同一个request重复构建EngineJob的措施。
// 那么EngineJob到底是什么东西,还是不知道
EngineJob> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
// 另外,cb这个参数类型是ResourceCallback,此处的cb实现类是SingleRequest,cb用来在请求complete的时候回调
// addCalback中会把这个job加到ResourceCallbacksAndExecutors中,最后也请求完成后会在EngineJob的notifyCallbacksOfResult方法中遍历cbs回调到之前添加cb(callback)中
current.addCallback(cb, callbackExecutor);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
// 此处构建EngineJob,通过EngineJob类的注释(* A class that manages a load by adding and removing callbacks for for the load and notifying callbacks when the load completes.)
// 大概知道这个类是管理一个请求的,包括添加和删除callback、请求结束后调用callback
EngineJob engineJob =
engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);
// 此处构建DecodeJob,这个类从注释可以知道,是用来对资源进行编码的
DecodeJob decodeJob =
decodeJobFactory.build(
glideContext,
model,
key,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
onlyRetrieveFromCache,
options,
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);
}
看下engine.start方法:
public synchronized void start(DecodeJob decodeJob) {
this.decodeJob = decodeJob;
// 如果是从缓存decode就使用缓存线程池进行工作,否则就使用其他线程池执行任务,这里的其他线程池,
// 可能是我们最初初始化Glide的时候创建的默认的线程池,也可能是用户设置的线程池
GlideExecutor executor = decodeJob.willDecodeFromCache()
? diskCacheExecutor
: getActiveSourceExecutor();
executor.execute(decodeJob);
}
最终调用了GlideExecutor的execute方法:
@Override
public void execute(@NonNull Runnable command) {
delegate.execute(command);
}
那么delegate的实现类是什么呢,就是start方法中获取的线程池类。假设是sourceExecutor那么便是初始化Glide 的时通过GlideExecutor.newSourceExecutor创建的。
我们execute方法执行的command是Runnable类型,就是我们传进来的decodeJob。他的run方法如下:
// We need to rethrow only CallbackException, but not other types of Throwables.
@SuppressWarnings("PMD.AvoidRethrowingException")
@Override
public void run() {
// This should be much more fine grained, but since Java's thread pool implementation silently
// swallows all otherwise fatal exceptions, this will at least make it obvious to developers
// that something is failing.
GlideTrace.beginSectionFormat("DecodeJob#run(model=%s)", model);
// Methods in the try statement can invalidate currentFetcher, so set a local variable here to
// ensure that the fetcher is cleaned up either way.
DataFetcher> localFetcher = currentFetcher;
try {
if (isCancelled) {
notifyFailed();
return;
}
runWrapped();
} catch (CallbackException e) {
// If a callback not controlled by Glide throws an exception, we should avoid the Glide
// specific debug logic below.
throw e;
} catch (Throwable t) {
// Catch Throwable and not Exception to handle OOMs. Throwables are swallowed by our
// usage of .submit() in GlideExecutor so we're not silently hiding crashes by doing this. We
// are however ensuring that our callbacks are always notified when a load fails. Without this
// notification, uncaught throwables never notify the corresponding callbacks, which can cause
// loads to silently hang forever, a case that's especially bad for users using Futures on
// background threads.
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "DecodeJob threw unexpectedly"
+ ", isCancelled: " + isCancelled
+ ", stage: " + stage, t);
}
// When we're encoding we've already notified our callback and it isn't safe to do so again.
if (stage != Stage.ENCODE) {
throwables.add(t);
notifyFailed();
}
if (!isCancelled) {
throw t;
}
throw t;
} finally {
// Keeping track of the fetcher here and calling cleanup is excessively paranoid, we call
// close in all cases anyway.
if (localFetcher != null) {
localFetcher.cleanup();
}
GlideTrace.endSection();
}
}
可以看到一个DataFetcher类型的变量localFetcher,他被赋值为currentFetcher,至于currentFetcher何时被赋值呢,有好几处,本人没有debug,暂不知道是哪里赋值的,尝试向下看。
仅有一个有用的方法了,便是runWrapper了:
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);
}
}
看起来是各种状态转换的逻辑。这个runReason的值是什么呢,init后他是INITIALIZE,所以走第一个分支,state初始值是null,通过getNextStage方法赋值:
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);
}
}
走第一个分支,得到赋值。假设此处赋值为Stage.RESOURCE_CACHE,那么runWrapped()中的currentGenerator赋值为什么呢?
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);
}
}
返回了ResourceCacheGenerator类型。runWrapped()中继续执行 runGenerators();方法:
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.
}
可以看到在while循环中不停的执行状态的转移。并不断执行currentGenerator.startNext():
currentGenerator有几个实现类,我们先看下SourceGenertor类的startNext:
@Override
public boolean startNext() {
// 数据不为空的时候将数据缓存,第一次的时候这里是null
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
cacheData(data); // 缓存到磁盘
}
// 第一次的时候这里是null,赋值是在上面的CacheData方法中赋值的
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;
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
后半部分就是网络请求的执行了,fetcher有很多实现类,我们看HttpUrlFetcher:
@Override
public void loadData(@NonNull Priority priority,
@NonNull DataCallback super InputStream> callback) {
long startTime = LogTime.getLogTime();
try {
InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
callback.onDataReady(result);
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Failed to load data for url", e);
}
callback.onLoadFailed(e);
} finally {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Finished http url fetcher fetch in " + LogTime.getElapsedMillis(startTime));
}
}
}
请求数据后回调到sourceGenerator中,假设请求成功,先从HttpUrlFetcher回调到sourceGenerator的onDataReady:
@Override
public void onDataReady(Object data) {
DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
dataToCache = data;
// We might be being called back on someone else's thread. Before doing anything, we should
// reschedule to get back onto Glide's thread.
cb.reschedule();
} else {
cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher,
loadData.fetcher.getDataSource(), originalKey);
}
}
然后又从sourceGenerator中继续回调到DecodeJob中(sourceGenerator是在这里创建的,创建set了callback),此处回调DecodeJob.onDataFetcherReady:
@Override
public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher> fetcher,
DataSource dataSource, Key attemptedKey) {
this.currentSourceKey = sourceKey;
this.currentData = data;
this.currentFetcher = fetcher;
this.currentDataSource = dataSource;
this.currentAttemptingKey = attemptedKey;
if (Thread.currentThread() != currentThread) {
runReason = RunReason.DECODE_DATA;
callback.reschedule(this);
} else {
GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
try {
decodeFromRetrievedData();
} finally {
GlideTrace.endSection();
}
}
}
private void decodeFromRetrievedData() {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Retrieved data", startFetchTime,
"data: " + currentData
+ ", cache key: " + currentSourceKey
+ ", fetcher: " + currentFetcher);
}
Resource resource = null;
try {
resource = decodeFromData(currentFetcher, currentData, currentDataSource);
} catch (GlideException e) {
e.setLoggingDetails(currentAttemptingKey, currentDataSource);
throwables.add(e);
}
if (resource != null) {
notifyEncodeAndRelease(resource, currentDataSource);
} else {
runGenerators();
}
}
在调用下面方法:
private void notifyComplete(Resource resource, DataSource dataSource) {
setNotifiedOrThrow();
callback.onResourceReady(resource, dataSource);
}
这个callback是Engine中load方法中构造decodeJob的时候传过来的,实现类是EngineJob,EngineJob的onResourceReady方法中最终调用了:
@Synthetic
void notifyCallbacksOfResult() {
ResourceCallbacksAndExecutors copy;
Key localKey;
EngineResource> localResource;
synchronized (this) {
stateVerifier.throwIfRecycled();
if (isCancelled) {
// TODO: Seems like we might as well put this in the memory cache instead of just recycling
// it since we've gotten this far...
resource.recycle();
release();
return;
} else if (cbs.isEmpty()) {
throw new IllegalStateException("Received a resource without any callbacks to notify");
} else if (hasResource) {
throw new IllegalStateException("Already have resource");
}
engineResource = engineResourceFactory.build(resource, isCacheable);
// Hold on to resource for duration of our callbacks below so we don't recycle it in the
// middle of notifying if it synchronously released by one of the callbacks. Acquire it under
// a lock here so that any newly added callback that executes before the next locked section
// below can't recycle the resource before we call the callbacks.
hasResource = true;
copy = cbs.copy();
incrementPendingCallbacks(copy.size() + 1);
localKey = key;
localResource = engineResource;
}
// listener是哪里传进来的?EngineJob的创建时使用Factory模式创建的,其factory的实现类是EngineJobFactory
// EngineJobFactory对象里面维护了一个listener变量,类型是EngineJobListener,那么EngineJobFactory对象实例化是在哪里进行的呢?
// 这个EngineJobFactory是在Engine的load方法中初始化的,传入的listener是this,显然,实现类是Engine
listener.onEngineJobComplete(this, localKey, localResource);
// 回调各个之前注册的callback
for (final ResourceCallbackAndExecutor entry : copy) {
entry.executor.execute(new CallResourceReady(entry.cb));
}
decrementPendingCallbacks();
}
上面的代码块中我发现listener的实现类是Engine,具体重写的方法是:
@SuppressWarnings("unchecked")
@Override
public synchronized void onEngineJobComplete(
EngineJob> engineJob, Key key, EngineResource> resource) {
// A null resource indicates that the load failed, usually due to an exception.
if (resource != null) {
resource.setResourceListener(key, this);
// 将当前正在使用的资源放入轻量级缓存中,我们前面有见过这个东西
if (resource.isCacheable()) {
activeResources.activate(key, resource);
}
}
// 前面在构建Engine的时候有提到过jobs,是为了避免重复构建job
jobs.removeIfCurrent(key, engineJob);
}
@Override
public synchronized void onEngineJobCancelled(EngineJob> engineJob, Key key) {
jobs.removeIfCurrent(key, engineJob);
}
继续看notifyCallbacksOfResult()方法的后半部分,遍历了copy,即cbs,cbs前面在Engine.load方法中有提到过,每个任务对应一个cb(ResourceCallback),jobs中存储的是cb和阈值对应的Executor,所以,此处最终通过遍历的方式回调了所有的cb。不要忘记cb的实现是SingleRequest类。分析下SingleRequest类中的onResourceReady方法:
/**
* Internal {@link #onResourceReady(Resource, DataSource)} where arguments are known to be safe.
*
* @param resource original {@link Resource}, never null
* @param result object returned by {@link Resource#get()}, checked for type and never null
*
*/
private synchronized void onResourceReady(Resource resource, R result, DataSource dataSource) {
// We must call isFirstReadyResource before setting status.
boolean isFirstResource = isFirstReadyResource();
status = Status.COMPLETE;
this.resource = resource;
if (glideContext.getLogLevel() <= Log.DEBUG) {
Log.d(GLIDE_TAG, "Finished loading " + result.getClass().getSimpleName() + " from "
+ dataSource + " for " + model + " with size [" + width + "x" + height + "] in "
+ LogTime.getElapsedMillis(startTime) + " ms");
}
isCallingCallbacks = true;
try {
boolean anyListenerHandledUpdatingTarget = false;
if (requestListeners != null) {
// 这个requestListeners可以通过RequestBuilder传入,如:
// GlideApp.with(context)
// .load(ResourceIds.raw.canonical)
// .listener(requestListener)
// .thumbnail(GlideApp.with(context)
// .load(thumbModel)
// .listener(requestListener)
// .override(100, 100)),
// imageView);
for (RequestListener listener : requestListeners) {
anyListenerHandledUpdatingTarget |=
listener.onResourceReady(result, model, target, dataSource, isFirstResource);
}
}
// targetListener 是通过Engine.load传进来的
anyListenerHandledUpdatingTarget |=
targetListener != null
&& targetListener.onResourceReady(result, model, target, dataSource, isFirstResource);
// 如果前面的targetListener返回false,才执行这里(这个思路类似view的点击事件体系)
if (!anyListenerHandledUpdatingTarget) {
// 这里的代码跟动画有关,我们看下target对象的实现类ImageViewTarget
Transition super R> animation =
animationFactory.build(dataSource, isFirstResource);
target.onResourceReady(result, animation);
}
} finally {
isCallingCallbacks = false;
}
notifyLoadSuccess();
}
target对象的实现类ImageViewTarget.onResourceReady:
@Override
public void onResourceReady(@NonNull Z resource, @Nullable Transition super Z> transition) {
if (transition == null || !transition.transition(resource, this)) {
setResourceInternal(resource);// 调用了view的设置资源的方法
} else {
maybeUpdateAnimatable(resource);// 调用了view的执行动画的方法
}
}
那么Transition是什么呢?他是一个接口,注释:
/**
* An interface that allows a transition to be applied to {@link android.view.View}s in {@link
* com.bumptech.glide.request.target.Target}s in across resource types. Targets that wrap views will
* be able to provide all of the necessary arguments and start the transition. Those that do not
* will be unable to provide the necessary arguments and will therefore be forced to ignore the
* transition. This interface is a compromise that allows view specific transition in Glide's
* complex world of arbitrary resource types and arbitrary target types.
*
* @param The type of the resource whose entrance will be transitioned.
*/
public interface Transition
大意是这个类允许一个transition(过度转换动画)应用到view上,但是得提供所需要的参数,否则会忽略这个transition。
实现类有:
具体怎么用,示例:
DrawableCrossFadeFactory drawableCrossFadeFactory = new DrawableCrossFadeFactory.Builder(300).setCrossFadeEnabled(true).build();
Glide.with(this)
.load(URL_JPG)
.apply(new RequestOptions().placeholder(R.drawable.ic_launcher))
.transition(DrawableTransitionOptions.with(drawableCrossFadeFactory))
.into(imageView);
至此基本上一个流程就走完了,但是一些细节依然没有深入其中。后面会继续阅读。