Glide最简单、标准的用法如下:
Glide.with(this) //第一步 (返回RequestManager对象)
.load(url) //第二步 (返回Y extends Target对象,主要是设置model这个属性)
.into(imageView); //第三步
本文,将根据Glide加载的with、load、into 这三个步骤从源码进入学习,如无特殊说明,源码版本均指:4.6.1
with()方法是Glide类中的一组静态方法,它有好几个方法重载,我们来看一下Glide类中所有with()方法的方法重载:
#Glide.class
@NonNull
public static RequestManager with(@NonNull Context context) {
return getRetriever(context).get(context);
}
@NonNull
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}
@NonNull
public static RequestManager with(@NonNull FragmentActivity activity) {
return getRetriever(activity).get(activity);
}
@NonNull
public static RequestManager with(@NonNull android.app.Fragment fragment) {
return getRetriever(fragment.getActivity()).get(fragment);
}
@NonNull
public static RequestManager with(@NonNull Fragment fragment) {
return getRetriever(fragment.getActivity()).get(fragment);
}
@NonNull
public static RequestManager with(@NonNull View view) {
return getRetriever(view.getContext()).get(view);
}
可以看到,with()方法的重载种类非常多,既可以传入Activity,也可以传入Fragment或者是Context,甚至View。每一个with()方法重载的代码都非常简单,都是先调用RequestManagerRetriever的静态get()方法得到一个RequestManagerRetriever对象,这个静态get()方法就是一个单例实现。然后再调用RequestManagerRetriever的实例get()方法,去获取RequestManager对象。
public class RequestManagerRetriever implements Handler.Callback {
.....
/**
* The top application level RequestManager.
*/
private volatile RequestManager applicationManager;
/**
* Pending adds for RequestManagerFragments.
*/
@VisibleForTesting
final Map<android.app.FragmentManager, RequestManagerFragment> pendingRequestManagerFragments =
new HashMap<>();
/**
* Pending adds for SupportRequestManagerFragments.
*/
@VisibleForTesting
final Map<FragmentManager, SupportRequestManagerFragment> pendingSupportRequestManagerFragments =
new HashMap<>();
/**
* Main thread handler to handle cleaning up pending fragment maps.
*/
private final Handler handler;
private final RequestManagerFactory factory;
@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) {
Glide glide = Glide.get(context.getApplicationContext());
applicationManager =
factory.build(
glide,
new ApplicationLifecycle(),
new EmptyRequestManagerTreeNode(),
context.getApplicationContext());
}
}
}
return applicationManager;
}
@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);
}
@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(activity, fm, null /*parentHint*/);
}
}
@NonNull
public RequestManager get(@NonNull Fragment fragment) {
Preconditions.checkNotNull(fragment.getActivity(),
"You cannot start a load on a fragment before it is attached or after it is destroyed");
if (Util.isOnBackgroundThread()) {
return get(fragment.getActivity().getApplicationContext());
} else {
FragmentManager fm = fragment.getChildFragmentManager();
return supportFragmentGet(fragment.getActivity(), fm, fragment);
}
}
@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, null /*parentHint*/);
}
}
@NonNull
public RequestManager get(@NonNull View view) {
if (Util.isOnBackgroundThread()) {
return get(view.getContext().getApplicationContext());
}
Preconditions.checkNotNull(view);
Preconditions.checkNotNull(view.getContext(),
"Unable to obtain a request manager for a view without a Context");
Activity activity = findActivity(view.getContext());
// The view might be somewhere else, like a service.
if (activity == null) {
return get(view.getContext().getApplicationContext());
}
if (activity instanceof FragmentActivity) {
Fragment fragment = findSupportFragment(view, (FragmentActivity) activity);
return fragment != null ? get(fragment) : get(activity);
}
// Standard Fragments.
android.app.Fragment fragment = findFragment(view, activity);
if (fragment == null) {
return get(activity);
}
return get(fragment);
}
@NonNull
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public RequestManager get(@NonNull android.app.Fragment fragment) {
if (fragment.getActivity() == null) {
throw new IllegalArgumentException(
"You cannot start a load on a fragment before it is attached");
}
if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
return get(fragment.getActivity().getApplicationContext());
} else {
android.app.FragmentManager fm = fragment.getChildFragmentManager();
return fragmentGet(fragment.getActivity(), fm, fragment);
}
}
private static void findAllSupportFragmentsWithViews(
@Nullable Collection<Fragment> topLevelFragments,
@NonNull Map<View, Fragment> result) {
if (topLevelFragments == null) {
return;
}
for (Fragment fragment : topLevelFragments) {
// getFragment()s in the support FragmentManager may contain null values, see #1991.
if (fragment == null || fragment.getView() == null) {
continue;
}
result.put(fragment.getView(), fragment);
findAllSupportFragmentsWithViews(fragment.getChildFragmentManager().getFragments(), result);
}
}
@Nullable
private Fragment findSupportFragment(@NonNull View target, @NonNull FragmentActivity activity) {
tempViewToSupportFragment.clear();
findAllSupportFragmentsWithViews(
activity.getSupportFragmentManager().getFragments(), tempViewToSupportFragment);
Fragment result = null;
View activityRoot = activity.findViewById(android.R.id.content);
View current = target;
while (!current.equals(activityRoot)) {
result = tempViewToSupportFragment.get(current);
if (result != null) {
break;
}
if (current.getParent() instanceof View) {
current = (View) current.getParent();
} else {
break;
}
}
tempViewToSupportFragment.clear();
return result;
}
@Nullable
private android.app.Fragment findFragment(@NonNull View target, @NonNull Activity activity) {
tempViewToFragment.clear();
findAllFragmentsWithViews(activity.getFragmentManager(), tempViewToFragment);
android.app.Fragment result = null;
View activityRoot = activity.findViewById(android.R.id.content);
View current = target;
while (!current.equals(activityRoot)) {
result = tempViewToFragment.get(current);
if (result != null) {
break;
}
if (current.getParent() instanceof View) {
current = (View) current.getParent();
} else {
break;
}
}
tempViewToFragment.clear();
return result;
}
@TargetApi(Build.VERSION_CODES.O)
private void findAllFragmentsWithViews(
@NonNull android.app.FragmentManager fragmentManager,
@NonNull ArrayMap<View, android.app.Fragment> result) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
for (android.app.Fragment fragment : fragmentManager.getFragments()) {
if (fragment.getView() != null) {
result.put(fragment.getView(), fragment);
findAllFragmentsWithViews(fragment.getChildFragmentManager(), result);
}
}
} else {
findAllFragmentsWithViewsPreO(fragmentManager, result);
}
}
private void findAllFragmentsWithViewsPreO(
@NonNull android.app.FragmentManager fragmentManager,
@NonNull ArrayMap<View, android.app.Fragment> result) {
int index = 0;
while (true) {
tempBundle.putInt(FRAGMENT_INDEX_KEY, index++);
android.app.Fragment fragment = null;
try {
fragment = fragmentManager.getFragment(tempBundle, FRAGMENT_INDEX_KEY);
} catch (Exception e) {
// This generates log spam from FragmentManager anyway.
}
if (fragment == null) {
break;
}
if (fragment.getView() != null) {
result.put(fragment.getView(), fragment);
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1) {
findAllFragmentsWithViews(fragment.getChildFragmentManager(), result);
}
}
}
}
@Nullable
private Activity findActivity(@NonNull Context context) {
if (context instanceof Activity) {
return (Activity) context;
} else if (context instanceof ContextWrapper) {
return findActivity(((ContextWrapper) context).getBaseContext());
} else {
return null;
}
}
@NonNull
private RequestManager fragmentGet(@NonNull Context context,
@NonNull android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint) {
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint);
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;
}
@NonNull
private RequestManager supportFragmentGet(@NonNull Context context, @NonNull FragmentManager fm,
@Nullable Fragment parentHint) {
SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);
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;
}
@NonNull
RequestManagerFragment getRequestManagerFragment(
@NonNull final android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint) {
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingRequestManagerFragments.get(fm);
if (current == null) {
current = new RequestManagerFragment();
current.setParentFragmentHint(parentHint);
pendingRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
@NonNull
SupportRequestManagerFragment getSupportRequestManagerFragment(
@NonNull final FragmentManager fm, @Nullable Fragment parentHint) {
SupportRequestManagerFragment current =
(SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingSupportRequestManagerFragments.get(fm);
if (current == null) {
current = new SupportRequestManagerFragment();
current.setParentFragmentHint(parentHint);
pendingSupportRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
.......
}
上面代码的位置,进行了适当调准。
代码虽然比较多,但逻辑很清晰。
RequestManagerRetriever类中看似有很多个get()方法的重载,什么Context参数,Activity参数,Fragment参数等等,实际上只有两种情况而已,即传入Application类型的参数,和传入非Application类型的参数。
另外,如果我们是在非主线程当中使用的Glide,那么不管你是传入的Activity还是Fragment,都会被强制当成Application来处理。
关于这部分细节,在掌握Glide(2) : 从源码看,Glide是如何关联生命周期的 已经在这篇文章中有详细介绍,本文只针对Glide的主流程。
回到主题,with()方法其实就是为了得到一个RequestManager对象而已,然后Glide会根据我们传入with()方法的参数来确定图片加载的生命周期。
从一中可知, Glide.with()
返回的是 RequestManager. 因此 Glide.with().into() 的源码,直接到RequestManager.class 中查找.
# RequestManager.class
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable Bitmap bitmap) {
return asDrawable().load(bitmap);
}
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable Drawable drawable) {
return asDrawable().load(drawable);
}
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable Uri uri) {
return asDrawable().load(uri);
}
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable File file) {
return asDrawable().load(file);
}
@SuppressWarnings("deprecation")
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable Integer resourceId) {
return asDrawable().load(resourceId);
}
@SuppressWarnings("deprecation")
@CheckResult
@Override
@Deprecated
public RequestBuilder<Drawable> load(@Nullable URL url) {
return asDrawable().load(url);
}
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable byte[] model) {
return asDrawable().load(model);
}
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable Object model) {
return asDrawable().load(model);
}
和with() 方法一样, load()方法也是有多种重载, 包括Bitmap 、Drawable、String 、Uri、File等多种类型。但发现它们都是调用 asDrawable() 的load,并将 load()方法中的参数以model传递。我们看一下 asDrawable()方法:
# RequestManager.class
@NonNull
@CheckResult
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
@NonNull
@CheckResult
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
可以看到,asDrawable()方法最后以 new 一个RequestBuilder 对象返回。
也就是说,asDrawable().load( ) 转入到 RequestBuilder .class 中的 load( )
# RequestBuilder.class
@NonNull
@CheckResult
@SuppressWarnings("unchecked")
@Override
public RequestBuilder<TranscodeType> load(@Nullable Object model) {
return loadGeneric(model);
}
@NonNull
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
可以发现,load()方法只是设置了model这个属性的值。
至此,load(url)方法全部结束。
从二中可知,into()
方法同样在 RequestBuilder .class
中。
# RequestBuilder.class
代码片1
@NonNull
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread();
Preconditions.checkNotNull(view);
RequestOptions requestOptions = this.requestOptions;
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( ---分析1A
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,requestOptions); ---分析1B
}
在上面代码第39行中,需要分为2部分进行分析,1A、1B,即
一是 into () 方法
二是 into()方法里面的
glideContext.buildImageViewTarget(view, transcodeClass),/*targetListener=*/ null,requestOptions
# RequestBuilder.class
代码片2
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
@NonNull RequestOptions options) {
Util.assertMainThread();
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
options = options.autoClone();
Request request = buildRequest(target, targetListener, options);
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;
}
第18行代码,获取此时是否有正在进行的Request请求,如果有,则进行逻辑判断,决定是否需要开启一个新的,还是复用之前的。如果没有,进行第19行代码的if循环中。
我们跳转if判断,先分析第36、37行代码。
点击第36行代码,发现跳转到 Target.class 的 setRequest方法中。但是,Target却是一个接口。需要找到它的实现类。
查看 Target的实现类你会发现,里面错综复杂。似乎陷入了不知所措的局面。
但你如果细看代码片2的第5行、6行代码就会发现,此方法中的target 类型是T。而整个代码片2的返回类型也是T。
但代码片1的返回类型是ViewTarget。 代码片1的第39行代码into方法专递到代码片2就是T类型。
换句话说,这里的T,就是 ViewTarget。
上面几段话有点饶,需要你根据return 细细琢磨一下。
通过 ViewTarget
也是可以验证出来的。
我们继续看 target.setRequest(request); 直接进入 ViewTarget.class方法中
# ViewTarget.class
@Override
public void setRequest(@Nullable Request request) {
setTag(request);
}
private void setTag(@Nullable Object tag) {
if (tagId == null) {
isTagUsedAtLeastOnce = true;
view.setTag(tag);
} else {
view.setTag(tagId, tag);
}
}
其实就是将Request和View做了一个绑定的关系,保存在View的tag之中。这步设置完成之后,就进入到了最后一步。track当前请求。即代码片2第37行代码:
#RequestManager.class
void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
TargetTracker和RequestTracker分别是对target和request做了一个管理。
TargetTracker类中更加简单,有点类似一个扩展的List结构,也就是保存了由当前RequestManager在处理的所有Target的集合。
而RequestTracker则是所有Request的集合,代码如下:
代码片3
# RequestTracker.class
public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
pendingRequests.add(request);
}
}
这个方法中,分为两种情况,isPaused变量标识界面是否处于onStop状态,如果此时还可见,则直接调用request#begin方法执行,否则则是加入到pendingRequests中,这里pendingRequests的作用仅仅是为了保证Request不被Gc,因为requests是一个WeakHashMap,如果不使用pendingRequests强引用缓存,那么这个请求就有可能被回收掉,这里是做了这样一个处理,就能保证这些request不被系统回收掉,同时在requests也一定存在。下面我们继续分析begin这个方法。
下面我们继续分析begin这个方法。
点击代码片3第8行代码的begin()方法,发现跳到Request.class 中。但Request却是一个接口。必须找到它的实现类才行。
我们看一下Resuest的实现类,如下:
通过三个实现类的命名,我们很容易猜测到 代码片3第8行代码的begin()方法中,Request类的实现类是SingleRequest。
但这里只是猜测。我们需要去验证我们的猜测。(这也是阅读源码很重要的一种思路与技巧)
其实request的初始化位置,在代码片2第16行,再次贴出代码片2。
# RequestBuilder.class
代码片2
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
@NonNull RequestOptions options) {
Util.assertMainThread();
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
options = options.autoClone();
Request request = buildRequest(target, targetListener, options);
.....(较前面的代码片2,删除部分代码)
requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request);
return target;
}
我们看一下16行代码的buildRequest方法:
# RequestBuilder.class
private Request buildRequest(
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
RequestOptions requestOptions) {
return buildRequestRecursive(
target,
targetListener,
/*parentCoordinator=*/ null,
transitionOptions,
requestOptions.getPriority(),
requestOptions.getOverrideWidth(),
requestOptions.getOverrideHeight(),
requestOptions);
}
我们接着看上面代码第8行代码:
# RequestBuilder.class
private Request buildRequestRecursive(
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
@Nullable RequestCoordinator parentCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
RequestOptions requestOptions) {
// 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(
target,
targetListener,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
requestOptions);
if (errorRequestCoordinator == null) {
return mainRequest;
}
.....
Request errorRequest = errorBuilder.buildRequestRecursive(
target,
targetListener,
errorRequestCoordinator,
errorBuilder.transitionOptions,
errorBuilder.requestOptions.getPriority(),
errorOverrideWidth,
errorOverrideHeight,
errorBuilder.requestOptions);
errorRequestCoordinator.setRequests(mainRequest, errorRequest);
return errorRequestCoordinator;
}
从这里开始,ThumbnailRequestCoordinator、ErrorRequestCoordinator、SingleRequest 其实都出现了。
代码的主思路还是很清晰,分别是 缩略图请求协助类、错误请求协助类、正常的请求类。他们的英文命名,也的确如此。关于这部分细节,大家可以从上述代码片开始。(都在RequestBuilder.class)。
这部分不是Glide执行流程的主流程,我们直接告诉结论:这里request的实现类是SingleRequest类。
回到代码片3第8行代码,即:
代码片3
# RequestTracker.class
public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
pendingRequests.add(request);
}
}
request.begin 也就是调用 SingleRequest类中的begin方法:
代码片4
# SingleRequest.class
@Override
public void begin() {
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));
}
}
这个方法中,先是对model进行判断,这个model此时就是我们传的那个url,如果为空,则直接load失败,然后是一些状态的检查和一些回调方法等,接下来判断size,如果是有效的,则触发去真正的请求,否则则是设置一个回调,等待view布局有size之后,再来触发请求,真正的请求其实就在onSizeReady中被得到执行。
这个方法中,首先检查状态是不是在等待size,如果不是,则表明size已经有了,下面则是更新状态到Status.RUNNING,进而去调用Engine根据参数,这里面包含了所有的参数信息,缓存,图片显示等等,然后去开始真正请求,网络、内存、磁盘缓存等等。这块的东西很复杂,暂且放一放,这块设计到一个结果的回调。
SingleRequest类有一个接口,ResourceCallback
public interface ResourceCallback {
/**
* Called when a resource is successfully loaded.
*
* @param resource The loaded resource.
*/
void onResourceReady(Resource<?> resource, DataSource dataSource);
/**
* Called when a resource fails to load successfully.
*
* @param e a non-null {@link GlideException}.
*/
void onLoadFailed(GlideException e);
}
实现是在SignleRequest中,具体代码大家可自行分析,显然,必须要做的一件事情是告诉Target此时的加载结果,再由Target去通知View做如何的展示,实际上,也是这样子实现的。具体细节这里不展开了。
我们还是回到begin方法。在代码片4第22行代码,我们看到了 target.onLoadStarted(getPlaceholderDrawable())
这里的onLoadStarted还是接口类 Target中的方法。在 第三部分 1A部分,我们分析了这里的 target对应的是ViewTarget实现类。我们直接在ViewTarget.class中找onLoadStarted方法。如下:
# ViewTarget.class
@CallSuper
@Override
public void onLoadStarted(@Nullable Drawable placeholder) {
super.onLoadStarted(placeholder);
maybeAddAttachStateListener();
}
第7行代码super方法跳转到父类,是一个空实现的方法。
第8行代码,是状态监听的方法。
又没找到我们想要的。
这时候,就涉及到代码片1B的分析了。
代码片1中1B的代码如下:
glideContext.buildImageViewTarget(view, transcodeClass),/*targetListener=*/ null,requestOptions
对应的代码分别如下:
#GlideContext.class
@NonNull
public <X> ViewTarget<ImageView, X> buildImageViewTarget(
@NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
#ImageViewTargetFactory.class
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)");
}
}
}
在load()方法中的 as传递的是 Drawable.class 即,这里执行上述代码第19、20行代码,
也就是说返回DrawableImageViewTarget类。
ImageViewTarget.class中onLoadStarted方法如下
# ImageViewTarget.class
@Override
public void onLoadStarted(@Nullable Drawable placeholder) {
super.onLoadStarted(placeholder);
setResourceInternal(null);
setDrawable(placeholder);
}
@Override
public void setDrawable(Drawable drawable) {
view.setImageDrawable(drawable);
}
这个方法的实现很简单,就是为view提前设置一些状态,比如placeholder信息等等,然后等待Engine后续的加载完成。
至此,这一块简单的流程就已经介绍结束,基本的加载流程和LifiCircle的东西想必有了一个初步的认识,从文章分析来看,最复杂的部分可能就是Engine根据参数来具体加载的过程了,后续继续分析。
在上述第12行代码中,加载出图片。在此,ImageView上面就已经能够正常的显示出图片了。
至此,Glide的执行流程,分析完毕。