提示:Glide源码比较多,也比较复杂,多看几遍就懂了。加油~~
一般用法:
Glide.with(getContext())
.load(url)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.placeholder(R.drawable.ic_default)
.into(newDrawableImageViewTarget(mAvatarImgView));
}
一 、with方法
1.1 Glide.with()
with()方法是Glide类中的一组静态方法,返回RequestManager对象,它有好几个方法重载,我们来看一下Glide类中所有with()方法的方法重载:
@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 Fragment fragment) {
return getRetriever(fragment.getContext()).get(fragment);
}
1.2 Glide.RequestManagerRetriever()
getRetriever()获取RequestManagerRetriever。
@NonNull
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
//必须要有一个上下文才能加载
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();
}
@NonNull
public RequestManagerRetriever getRequestManagerRetriever() {
return requestManagerRetriever;
}
1.3 Glide.get(context):
@NonNull
public static Glide get(@NonNull Context context) {
...
//初始化Glide
checkAndInitializeGlide(context,annotationGeneratedModule);
...
}
return glide;
}
private static void checkAndInitializeGlide(
@NonNull Context context, @Nullable GeneratedAppGlideModule generatedAppGlideModule) {
//glide不能初始化两次
if (isInitializing) {
throw new IllegalStateException(
"You cannot call Glide.get() in registerComponents(),"
+ " use the provided Glide instance instead");
}
isInitializing = true;
initializeGlide(context, generatedAppGlideModule);
isInitializing = false;
}
private static void initializeGlide(@NonNull Context context,@NonNull GlideBuilder builder,@Nullable GeneratedAppGlideModuleannotationGeneratedModule){
...
//创建RequestManagerRetriever.RequestManagerFactory
RequestManagerRetriever.RequestManagerFactory factory =
annotationGeneratedModule != null
? annotationGeneratedModule.getRequestManagerFactory()
: null;
builder.setRequestManagerFactory(factory);
//这个builder就是GlideBuilder,用来构建Glide对象
Glide glide = builder.build(applicationContext);
}
1.4 接着看GlideBuilder类中build方法:
@NonNull
Glide build(@NonNull Context context) {
//sourceExecutor是进行网络请求的执行器
if (sourceExecutor == null) {
sourceExecutor = GlideExecutor.newSourceExecutor();
}
//diskCacheExecutor磁盘缓存执行器,后面从磁盘获取缓存数据用到
if (diskCacheExecutor == null) {
diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
}
if (animationExecutor == null) {
animationExecutor = GlideExecutor.newAnimationExecutor();
}
if (memorySizeCalculator == null) {
memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
}
if (connectivityMonitorFactory == null) {
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) {
diskCacheFactory = new InternalCacheDiskCacheFactory(context);
}
//构建执行引擎
if (engine == null) {
engine =
new Engine(
memoryCache,
diskCacheFactory,
diskCacheExecutor,
sourceExecutor,
GlideExecutor.newUnlimitedSourceExecutor(),
animationExecutor,
isActiveResourceRetentionAllowed);
}
if (defaultRequestListeners == null) {
defaultRequestListeners = Collections.emptyList();
} else {
defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners);
}
//构建了一个RequestManagerRetriever对象
RequestManagerRetriever requestManagerRetriever =
new RequestManagerRetriever(requestManagerFactory);
//构建Glide对象,并将上面初始化时创建的各种功能类封装进去
return new Glide(
context,
engine,
memoryCache,
bitmapPool,
arrayPool,
requestManagerRetriever,
connectivityMonitorFactory,
logLevel,
defaultRequestOptionsFactory,
defaultTransitionOptions,
defaultRequestListeners,
isLoggingRequestOriginsEnabled,
isImageDecoderEnabledForBitmaps);
}
以上就是初始化Glide、并构建Engine对象、还有各种线程池、各种缓存执行器等
1.5 RequestManagerRetriever.get()
接着上面继续,通过RequestManagerRetriever的get方法获取RequestManager对象
通过上下文类型分别走不同的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 ContextWrap
&& ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
return get(((ContextWrapper) context).getBaseContext());
}
}
return getApplicationManager(context);
}
@SuppressWarnings("deprecation")
@NonNull
public RequestManager get(@NonNull Activity activity) {
if (Util.isOnBackgroundThread()) {
//如果是是在子线程执行,让走ApplicationContext的get方法,也就是说生命周期跟application保持一致。else里面先判断activity是否destroyed
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
//fragmentGet方法里面将glide内置的一个不可见的fragment跟当前的activity绑定
return fragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
以传入上下文是Activity为例,继续查看是怎么得到RequestManager的,factory就是RequestManagerFactory对象
private RequestManager fragmentGet(
@NonNull Context context,
@NonNull android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
//这个current就是glide自己的fragment,用来绑定生命周期的。
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
Glide glide = Glide.get(context);
requestManager =
// private final RequestManagerFactory factory;
//current.getGlideLifecycle()是glide潜入的frgament的生命周期监听类
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}
RequestManagerFactory是一个接口,build方法的参数里面传入了Lifecycle对象。这个Lifecycle是用来监听内潜fragment的生命周期的。
public interface RequestManagerFactory {
@NonNull
RequestManager build(
@NonNull Glide glide,
@NonNull Lifecycle lifecycle,
@NonNull RequestManagerTreeNode requestManagerTreeNode,
@NonNull Context context);
}
private static final RequestManagerFactory DEFAULT_FACTORY =
new RequestManagerFactory() {
@NonNull
@Override
public RequestManager build(
@NonNull Glide glide,
@NonNull Lifecycle lifecycle,
@NonNull RequestManagerTreeNode requestManagerTreeNode,
@NonNull Context context) {
return new RequestManager(glide, lifecycle, requestManagerTreeNode, context);
}
};
RequestManagerRetriever类中看似有很多个get()方法的重载,什么Context参数,Activity参数,Fragment参数等等,实际上只有两种情况而已,即传入Application类型的参数,和传入非Application类型的参数。
如果在Glide.with()方法中传入的是一个Application对象,它自动就是和应用程序的生命周期是同步的,如果应用程序关闭的话,Glide的加载也会同时终止。
如果在Glide.with()方法中传入非Application参数,那就是会向当前的Activity当中添加一个隐藏的Fragment,这个隐藏的Fragment的生命周期就和当前Activity的生命周期绑定了。
如果我们是在非主线程当中使用的Glide,那么不管你是传入的Activity还是Fragment,都会被强制当成Application来处理。
界面不可见或者销毁的时候,通过这样的方法还能避免Glide持有Activity的实例而发生内存泄漏问题。
小结:
with()方法传入当前环境,是为了让图片加载保持生命周期同步。并且返回RequestManager对象供load()方法使用。RequestManager能够用于管理和启动对Glide的请求。还可以控制生命周期事件智能地停止,启动和重新启动请求.
2、load()方法
2.1 RequestManager.load()
因为gilde支持很多图片来源。所以load方法也有很多重栽方法。
load()方法是在RequestManager里面。
//加载Bitmap
public RequestBuilder load(@Nullable Bitmap bitmap) {
return asDrawable().load(bitmap);
}
//加载Drawable
@Override
public RequestBuilder load(@Nullable Drawable drawable) {
return asDrawable().load(drawable);
}
//加载字符串地址
@Override
public RequestBuilder load(@Nullable String string) {
return asDrawable().load(string);
}
//加载字uri
@Override
public RequestBuilder load(@Nullable Uri uri) {
return asDrawable().load(uri);
}
//加载字File
@Override
public RequestBuilder load(@Nullable File file) {
return asDrawable().load(file);
}
//加载字本地图资源
@Override
public RequestBuilder load(@RawRes @DrawableRes @Nullable Integer resourceId) {
return asDrawable().load(resourceId);
}
//加载字url
@Override
@Deprecated
public RequestBuilder load(@Nullable URL url) {
return asDrawable().load(url);
}
//加载字字节数组
@Override
public RequestBuilder load(@Nullable byte[] model) {
return asDrawable().load(model);
}
//我们如果不指定类型的话,默认是Drawable
public RequestBuilder asDrawable() {
return as(Drawable.class);
}
//如果需要显示gif时
public RequestBuilder asGif() {
return as(GifDrawable.class).apply(DECODE_TYPE_GIF);
}
//如果需要显示Bitmap时
public RequestBuilder asBitmap() {
return as(Bitmap.class).apply(DECODE_TYPE_BITMAP);
}
public RequestBuilder as(
@NonNull Class resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
as asDrawable()返回的就是RequestBuilder对象。
我们以网络获取图片为例,传入String,看在RequestBuilder类里面的load方法
@NonNull
@Override
@CheckResult
public RequestBuilder load(@Nullable String string) {
return loadGeneric(string);
}
@NonNull
private RequestBuilder loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
loadGeneric方法返回RequestBuilder本身,mode就是传入的加载类型,也就是字符串,将mode赋值给RequestBuilder的成员变量。
isModelSet是后面用来判断调用into方法的,必须在into之前调用load方法。
2.2 RequestBuilder
public class RequestBuilder extends BaseRequestOptions>{
protected static final RequestOptions DOWNLOAD_ONLY_OPTIONS =
new RequestOptions()
.diskCacheStrategy(DiskCacheStrategy.DATA)
.priority(Priority.LOW)
.skipMemoryCache(true);
protected RequestBuilder(
@NonNull Glide glide,
RequestManager requestManager,
//资源类型,我们以String为例,transcodeClass就是String类;
Class transcodeClass,
Context context) {
this.glide = glide;
this.requestManager = requestManager;
this.transcodeClass = transcodeClass;
this.context = context;
this.transitionOptions = requestManager.getDefaultTransitionOptions(transcodeClass);
this.glideContext = glide.getGlideContext();
initRequestListeners(requestManager.getDefaultRequestListeners());
apply(requestManager.getDefaultRequestOptions());
}
RequestBuilder继承自BaseRequestOptions,BaseRequestOptions里面就是一些需要的配置
比如:设置是否跳过缓存,是否磁盘缓存,展位图等。我们传入自己的配置即可。
Glide.with(getContext())
.load(url)
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.placeholder(R.drawable.ic_default)
.into(newDrawableImageViewTarget(mAvatarImgView));
小结:
1、load方法用来传入加载的图片资源路径。
2、再调load方法之前需要设置请求类型是gif或者Bitmap,不设置默认时Drawable。
3、load之后需要设置请求的一些配置参数。是否使用缓存,展位图等。
4、最终返回的是配置好请求类型的RequestBuilder,用来进行下一步into调用。
3、into()方法
3.1 RequestBuilder.into()
@NonNull
public ViewTarget into(@NonNull ImageView view) {
//先判断是否在主线程
Util.assertMainThread();
//检测imageView是否为null
Preconditions.checkNotNull(view);
//获取配置好的RequestOptions,再配置imageView的缩放类型。
BaseRequestOptions> requestOptions = this;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
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(
//构建Target:DrawableImageViewTarget(view)或者是BitmapImageViewTarget(view)
//因为我们默认是Drawable,所以transcodeClass是Drawable.class
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
//配置好的请求参数
requestOptions,
//主线程执行器,Executors的构造方法里面有:Handler handler = new Handler(Looper.getMainLooper());
Executors.mainThreadExecutor());
}
看一下GlideContext的buildImageViewTarget方法,参数是我们的控件View和最终转码类型的字节码
GlideContext类是在Glide初始化的最后构建的,用来全局提供Glide构建的配置类对象的,比如它的getEngine()方法,返回Engine对象。
3.1.1 GlideContext.buildImageViewTarget
@NonNull
public ViewTarget buildImageViewTarget(
@NonNull ImageView imageView, @NonNull Class transcodeClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
3.1.2 ImageViewTargetFactory.buildTarget
通过传入的资源转码类型去创建不同的Target:
new BitmapImageViewTarget(view)和
new DrawableImageViewTarget(view);
*/
public class ImageViewTargetFactory {
public ViewTarget buildTarget(
@NonNull ImageView view, @NonNull Class clazz) {
if (Bitmap.class.equals(clazz)) {
return (ViewTarget) new BitmapImageViewTarget(view);
} else if (Drawable.class.isAssignableFrom(clazz)) {
return (ViewTarget) new DrawableImageViewTarget(view);
} else {
throw new IllegalArgumentException(
"Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
}
}
}
3.1.3 DrawableImageViewTarget
看下DrawableImageViewTarget类,有个setResource()方法,这玩意应该就是最后将获取到的资源图片显示到控件的方法了。
public class DrawableImageViewTarget extends ImageViewTarget {
public DrawableImageViewTarget(ImageView view) {
super(view);
}
/** @deprecated Use {@link #waitForLayout()} instead. */
// Public API.
@SuppressWarnings({"unused", "deprecation"})
@Deprecated
public DrawableImageViewTarget(ImageView view, boolean waitForLayout) {
super(view, waitForLayout);
}
@Override
protected void setResource(@Nullable Drawable resource) {
view.setImageDrawable(resource);
}
}
3.1.4 Executors.mainThreadExecutor()
构造器里创建了主线程的handle对象,再exectue执行后,handle.post(command)将数据传递到主线程
public final class Executors {
private Executors() {
// Utility class.
}
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);
}
};
private static final Executor DIRECT_EXECUTOR =
new Executor() {
@Override
public void execute(@NonNull Runnable command) {
command.run();
}
};
/** Posts executions to the main thread. */
public static Executor mainThreadExecutor() {
return MAIN_THREAD_EXECUTOR;
继续return的into方法
3.2 RequestBuilder.into()
private > Y into(
//在GlideContext中创建的target
@NonNull Y target,
//null
@Nullable RequestListener targetListener,
//requestBuilder配置的参数
BaseRequestOptions> options,
//主线程执行器
Executor callbackExecutor) {
Preconditions.checkNotNull(target);
//isModelSet的作用。
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
//通过我们传入的参数调buildRequest方法,返回一个request,callbackExecutor含有绑定主线程的Handler
Request request = buildRequest(target, targetListener, options, callbackExecutor);
//在给target设置request之前,看下这个target之前有没有老的request。
Request previous = target.getRequest();
//如果两个request等价,并且老的request有设置缓存,并且老request的不为null,并且不在Running中,就调用request的begin()方法,让他开始加载。并返回这个target。
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
if (!Preconditions.checkNotNull(previous).isRunning()) {
previous.begin();
}
return target;
}
//如果上面判断不成立。则clear老的request,将新的request设置给target。并且执行 requestManager.track()方法。返回target。
requestManager.clear(target);
==target==.setRequest(request);
requestManager.track(target, request);
return target;
}
注意:Request类是个接口,本身有start,pause,clear,isRunning,isComplete,isEquivalentTo等方法。我们这里最终返回的Request就是后面说的==SingleRequest==对象。
** 3.2.1 说这个buildRequest方法之前,解释一下requestManager.track这个方法**
synchronized void track(@NonNull Target> target, @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
3.2.2 看下TargetTracker类:
==TargetTracker实现LifecycleListener接口==,里面创建了一个targets集合。这个类的作用就是将所有的target添加到集合,并在生命周期变化时管理它。
public final class TargetTracker implements LifecycleListener {
// targets是一个具有映射关系的set无序集合。key就是target。
//WeakHashMap也是一种hashmap,特点就是它的key是弱键,当key不使用的时候可以被回收。
private final Set> targets =
Collections.newSetFromMap(new WeakHashMap, Boolean>());
//追踪,将target add到集合里面。
public void track(@NonNull Target> target) {
targets.add(target);
}
public void untrack(@NonNull Target> target) {
targets.remove(target);
}
@Override
public void onStart() {
for (Target> target : Util.getSnapshot(targets)) {
target.onStart();
}
}
@Override
public void onStop() {
for (Target> target : Util.getSnapshot(targets)) {
target.onStop();
}
}
3.2.3 RequestTracker
在看 RequestTracker.runRequest方法之前,先看下RequestTracker这个类:
==RequestTracker是个管理request的工具类==
public class RequestTracker {
//将所有的request放入到一个有映射关系的set集合中,用来控制reuqest的行为
private final Set requests =Collections.newSetFromMap(new WeakHashMap());
//排队等待执行的request的集合
private final List pendingRequests = new ArrayList<>();
//执行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到集合
@VisibleForTesting
void addRequest(Request request) {
requests.add(request);
}
//clearAndRemove集合中的request
public boolean clearAndRemove(@Nullable Request request) {
...
}
//暂停request
public void pauseRequests() {
....
}
//暂停所有的request
public void pauseAllRequests() {
...
}
public void resumeRequests() {
...
}
public void clearRequests() {
...
}
public void restartRequests() {
....
}
}
3.2.4 再看 ==RequestTracker.runRequest==方法:
public void runRequest(@NonNull Request request) {
//将request添加到集合
//private final Set requests =
Collections.newSetFromMap(new WeakHashMap());====
requests.add(request);
//如果没有暂停,执行request的begin方法。这里request就是后面说的SingerRequest对象。
if (!isPaused) {
request.begin();
} else {
//如果在暂停,执行clear方法 :target.removeCallback(this);
request.clear();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
}
// private final List pendingRequests = new ArrayList<>();
//放入挂起集合里面等待
pendingRequests.add(request);
}
}
具体的执行请求逻辑在后面的SingerRequest中。
** 3.3 继续看RequestBuilder.buildRequest方法:**
private Request buildRequest(
Target target,
@Nullable RequestListener targetListener,
BaseRequestOptions> requestOptions,
Executor callbackExecutor) {
return buildRequestRecursive(
/*requestLock=*/ new Object(),
target,
targetListener,
/*parentCoordinator=*/ null,
transitionOptions,
requestOptions.getPriority(),
requestOptions.getOverrideWidth(),
requestOptions.getOverrideHeight(),
requestOptions,
callbackExecutor);
private Request buildRequestRecursive(
Object requestLock,
Target target,
@Nullable RequestListener targetListener,
@Nullable RequestCoordinator parentCoordinator,
TransitionOptions, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
BaseRequestOptions> requestOptions,
Executor callbackExecutor) {
Request mainRequest =
buildThumbnailRequestRecursive(
requestLock,
target,
targetListener,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
requestOptions,
callbackExecutor);
private Request buildThumbnailRequestRecursive(
Object requestLock,
Target target,
RequestListener targetListener,
@Nullable RequestCoordinator parentCoordinator,
TransitionOptions, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
BaseRequestOptions> requestOptions,
Executor callbackExecutor) {
...
//这里省去了许多处理缩略图的代码。
return obtainRequest(
requestLock,
target,
targetListener,
requestOptions,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
}
}
3.3.1 以上代码主要都是在处理缩略图的。我们看主要的主线逻辑。最后return了obtainRequest方法。
private Request obtainRequest(
Object requestLock,
Target target,
RequestListener targetListener,
BaseRequestOptions> requestOptions,
RequestCoordinator requestCoordinator,
TransitionOptions, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
Executor callbackExecutor) {
//这才是重点,最后返回的就是这个SingleRequest对象
return SingleRequest.obtain(
context,
glideContext,
requestLock,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
glideContext.getEngine(),
transitionOptions.getTransitionFactory(),
callbackExecutor);
}
obtainRequest()方法来获取一个Request对象.obtainRequest()方法有调用了SingleRequest.obtain方法,传入之前配置好的参数各种参数。这些参数其实都是组装到Request对象中了。
3.3.2 SingleRequest
==再看下SingleRequest类==,SingleRequest.obtain的之后就是SingleRequest的初始化操作并且参数赋值。这个SingleRequest就是要返回的request。
public final class SingleRequest implements Request, SizeReadyCallback, ResourceCallback {
private SingleRequest(
Context context,
GlideContext glideContext,
@NonNull Object requestLock,
@Nullable Object model,
Class transcodeClass,
BaseRequestOptions> requestOptions,
int overrideWidth,
int overrideHeight,
Priority priority,
Target target,
@Nullable RequestListener targetListener,
@Nullable List> requestListeners,
RequestCoordinator requestCoordinator,
Engine engine,
TransitionFactory super R> animationFactory,
Executor callbackExecutor) {
this.requestLock = requestLock;
this.context = context;
this.glideContext = glideContext;
this.model = model;
this.transcodeClass = transcodeClass;
this.requestOptions = requestOptions;
this.overrideWidth = overrideWidth;
this.overrideHeight = overrideHeight;
this.priority = priority;
this.target = target;
this.targetListener = targetListener;
this.requestListeners = requestListeners;
this.requestCoordinator = requestCoordinator;
this.engine = engine;
this.animationFactory = animationFactory;
this.callbackExecutor = callbackExecutor;
status = Status.PENDING;
if (requestOrigin == null && glideContext.isLoggingRequestOriginsEnabled()) {
requestOrigin = new RuntimeException("Glide request origin trace");
}
}
==RequestTracker的runRequest中回调用begin方法(3.2.4中):==
@Override
public void begin() {
synchronized (requestLock) {
assertNotCallingCallbacks();
//确定对象没有被回收
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
// model(url)为空,回调加载失败
if (model == null) {
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
width = overrideWidth;
height = overrideHeight;
}
}
if (status == Status.RUNNING) {
throw new IllegalArgumentException("Cannot restart a running request");
}
if (status == Status.COMPLETE) {
onResourceReady(resource, DataSource.MEMORY_CACHE);
return;
}
//初始化状态
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
//如果已经设置好width
onSizeReady(overrideWidth, overrideHeight);
} else {
//通过回调去监界面渲染完成时获取view的大小( ViewTreeObserver observer = view.getViewTreeObserver();)
//还是会调用onSizeReady
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));
}
}
}
3.3.3 SingleRequest.onSizeReady
SingleRequest.begin()方法是真正的请求入口;确保ImageView大小获取到后,调用SingleRequest的onSizeReady()方法,继续:
public void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
synchronized (requestLock) {
if (IS_VERBOSE_LOGGABLE) {
logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
//imager的大小还不确定直接return
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));
}
//这里的engine 是在创建Glide的build()方法中 创建的(第一节1.4),engine封装了各种Executor,内存缓存等
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);
if (status != Status.RUNNING) {
loadStatus = null;
}
}
}
3.4 Engine
继续Engine的load方法:
这里开始图片的请求,图片的三级缓存的功能也在这里
这里我们先定义一下三级缓存:
1、弱引用缓存:使用弱引用,来缓存图片,图片被回收后,会保存到内存缓存中。
2、内存缓存LruCache:(默认是在创建Glide的时候创建的,也可自定义), 如果弱引用缓存找不到图片,就从内存缓存中查找,找到图片后,删除内存缓存(防止因Lru的策略,图片正在使用,但是被回收掉的问题)。
3、磁盘缓存 :上面两级缓存都没有图片,如果在磁盘缓存中找到,就把图片加载后,放到弱引用缓存中。磁盘缓存数据的种类有两种,一种是缓存源数据,这种数据需要经过解析才能得到图片。一种是图片数据,直接加载进来就可以用的。可以通过diskCacheStrategyOf 来自由选择如何缓存
public 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,以后就根据这个key,在缓存中查找
EngineKey key =
keyFactory.buildKey(
model,
signature,
width,
height,
transformations,
resourceClass,
transcodeClass,
options);
//从内存里面找是否有目标图片(包括弱应用缓存和内存缓存)
EngineResource> memoryResource;
synchronized (this) {
memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
//如果内存里面没有,进入waitForExistingOrStartNewJob方法:
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);
}
}
//如果内存中能找到,则直接回调出去
cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE);
return null;
3.4.1
==内存中找到的话,将数据回调到SingleReuest的onResourceReady方法,最最终通过target将展示图片到控件。==
@GuardedBy("requestLock")
private 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 (!anyListenerHandledUpdatingTarget) {
Transition super R> animation = animationFactory.build(dataSource, isFirstResource);
//在这里,通过我们之前创建的DrawableImageViewTarget,他继承自ImageViewTarget,ImageViewTarget有个抽象方法就是onResourceReady(),最终将将图片显示到控件上。
target.onResourceReady(result, animation);
}
} finally {
isCallingCallbacks = false;
}
notifyLoadSuccess();
}
3.5 从内存里面找
@Nullable
private EngineResource> loadFromMemory(
EngineKey key, boolean isMemoryCacheable, long startTime) {
if (!isMemoryCacheable) {
return null;
}
//检查是弱引用缓存中否有目标图片
EngineResource> active = loadFromActiveResources(key);
if (active != null) {
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return active;
}
//检查内存的缓存 是否有目标图片
EngineResource> cached = loadFromCache(key);
if (cached != null) {
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return cached;
}
return null;
}
3.5.1 Engine.loadFromActiveResources()
@Nullable
private EngineResource> loadFromActiveResources(Key key) {
//activeResources获取弱应用缓存
EngineResource> active = activeResources.get(key);
if (active != null) {
active.acquire();
}
return active;
}
3.5.2 ActiveResources 弱引用缓存
class ActiveResources {
//这个map就是ActiveResources里面用来保存弱应用缓存的
Map activeEngineResources = new HashMap<>();
@Nullable
synchronized EngineResource> get(Key key) {
ResourceWeakReference activeRef = activeEngineResources.get(key);
if (activeRef == null) {
return null;
}
//找到弱应用对象,get到EngineResource返回
EngineResource> active = activeRef.get();
if (active == null) {
cleanupActiveReference(activeRef);
}
return active;
}
//ResourceWeakReference是ActiveResources的内部类,继承WeakReference
static final class ResourceWeakReference extends WeakReference> {
final Key key;//缓存key
final boolean isCacheable;
Resource> resource;//缓存resource
}
ActiveResources是保存活动资源的一个类,它里面有个内部类ResourceWeakReference,这个ResourceWeakReference继承WeakReference。
这个ActiveResources里面有一个value是ResourceWeakReference类型的map,它主要保存的就是活动的资源,我们叫他弱应用缓存。缓存是先从弱应用缓存中查找,没找到再去内存缓存中查找。
再看下这个弱应用缓存是什么时候存进去的?
//1、弱应用缓存没找到,就会去内存缓存找,内存缓存找到后保存到弱应用缓存
private EngineResource> loadFromCache(Key key) {
EngineResource> cached = getEngineResourceFromCache(key);
if (cached != null) {
cached.acquire();
//这个方法就是往弱应用缓存map中存数据
activeResources.activate(key, cached);
}
return cached;
}
//2、当内存缓存中都没有找到,那就去磁盘中找,在没有的就去网络获取,这时候获取到资源并且展示完成后再存到弱应用缓存中。
@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.isMemoryCacheable()) {
activeResources.activate(key, resource);
}
jobs.removeIfCurrent(key, engineJob);
}
3.6 如果缓存里面没有,则走下面方法,从磁盘或者网络获取
//执行一个新的job
private LoadStatus waitForExistingOrStartNewJob(
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,
EngineKey key,
long startTime) {
//在弱引用和内存缓存中,都没有找到图片,就执行任务。
//这个任务,会现在磁盘缓存中查找,因为磁盘读取耗时较大,所以放在任务线程中
EngineJob> current = jobs.get(key, onlyRetrieveFromCache);
//如果current不等于null,说明这个engineJob已经在执行了,不用再次构建
if (current != null) {
current.addCallback(cb, callbackExecutor);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
//创建一个新的engineJob对象,它里面有很多Executor,用来加载异步图片
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内部维护的存放任务的HashMap中(3.6.1),
jobs.put(key, engineJob);
// 注册ResourceCallback接口,就是在成功获取图片后,需要显示到ImageView 上的回调,这个接口回调到SingleRequest 中
engineJob.addCallback(cb, callbackExecutor);
//开始执行
engineJob.start(decodeJob);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
3.6.1 Jobs
Jobs里面维护了两个map,一个新job,一个缓存job。
final class Jobs {
private final Map> jobs = new HashMap<>();
private final Map> onlyCacheJobs = new HashMap<>();
@VisibleForTesting
Map> getAll() {
return Collections.unmodifiableMap(jobs);
}
EngineJob> get(Key key, boolean onlyRetrieveFromCache) {
return getJobMap(onlyRetrieveFromCache).get(key);
}
void put(Key key, EngineJob> job) {
getJobMap(job.onlyRetrieveFromCache()).put(key, job);
}
void removeIfCurrent(Key key, EngineJob> expected) {
Map> jobMap = getJobMap(expected.onlyRetrieveFromCache());
if (expected.equals(jobMap.get(key))) {
jobMap.remove(key);
}
}
private Map> getJobMap(boolean onlyRetrieveFromCache) {
return onlyRetrieveFromCache ? onlyCacheJobs : jobs;
}
}
3.7 继续EngineJob中的start方法:
public synchronized void start(DecodeJob decodeJob) {
this.decodeJob = decodeJob;
//若能从磁盘缓存获取数据,就使用diskCacheExecutor,否则在根据其他的条件判断使用哪个Executor
//ture:有缓存,则使用磁盘缓存线程池。否则返回数据源线程池;
GlideExecutor executor =
decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
//执行decodeJob的run方法
executor.execute(decodeJob);
}
通过上面start()方法知道是去磁盘取还是网络获取,对应执行器再去执行这个decodeJob。
3.8 DecodeJob
这个类负责从磁盘或数据源解码资源,并应用转换和转码。
在看下DecodeJob的willDecodeFromCache方法:
boolean willDecodeFromCache() {
Stage firstStage = getNextStage(Stage.INITIALIZE);
//如果此作业将尝试从磁盘缓存解码资源,则返回 true,如果它始终从源解码,则返回 false。
return firstStage == Stage.RESOURCE_CACHE || firstStage == Stage.DATA_CACHE;
}
3.8.1 获取下一个阶段从哪里获取数据
private Stage getNextStage(Stage current) {
switch (current) {
//若配置的缓存策略允许从磁盘缓存的资源中读取数据,则返回Stage.RESOURCE_CACHE
case INITIALIZE:
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE
: getNextStage(Stage.RESOURCE_CACHE);
//若配置的缓存策略允许从磁盘缓存的源数据缓存读取数据,则返回Stage.DATA_CACHE
case RESOURCE_CACHE:
return diskCacheStrategy.decodeCachedData()
? Stage.DATA_CACHE
: getNextStage(Stage.DATA_CACHE);
//若只能允许从缓存中读取数据,则直接FINISH,否则返回Stage.SOURCE,表示加载新的资源
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);
}
}
注意:磁盘缓存了两种资源,一种是数据源缓存,一种是磁盘的资源缓存
3.8.2 DecodeJob.run()
public void run() {
GlideTrace.beginSectionFormat("DecodeJob#run(model=%s)", model);
DataFetcher> localFetcher = currentFetcher;
try {
if (isCancelled) {
notifyFailed();
return;
}
//主要看这:
runWrapped();
} catch (CallbackException e) {
} finally {
if (localFetcher != null) {
localFetcher.cleanup();
}
GlideTrace.endSection();
}
}
3.8.3 DecodeJob.runWrapped():
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);
}
}
首先从磁盘中去数据。如果磁盘的资源缓存或者磁盘的数据源缓存任意一个没有取到缓存,则就去网络请求数据。
该类继承了DataFetcherGenerator, 这是一个数据获取生成器。
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);
}
}
这三个数据抓取执行器分别是:磁盘资源缓存执行器、磁盘数据源执行器、网络元数据执行器;通过这个stage去选择哪一个执行器。
3.8.4 DecodeJob.runGenerators()
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
//判断逻辑主要看startNext方法,这个方法回去执行不同执行器的startNext方法。
// 返回值是个布尔值,如果返回true,说明刚才的执行器获取到了缓存,然后去解码,回调出去,如果返回false,则执行Stage.SOURCE的逻辑,走reschedule()方法
while (!isCancelled&& currentGenerator != null && !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
if (stage == Stage.SOURCE) {
reschedule();
return;
}
}
if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
}
}
@Override
public void reschedule() {
//我们想从磁盘缓存服务切换到源执行器。
runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
callback.reschedule(this);
}
runReason改变之后,reschedule方法执行的就是网络获取执行器的逻辑了,
3.8.5 获取网络图片
所以执行SourceGenerator.startNext方法:
@Override
public boolean startNext() {
...
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
//从DecodeHelper的数据加载集合中, 获取一个数据加载器 ModelLoader
//这些ModelLoader 包括默认的和自定义的
// 这里的符合条件就是判断在load()传入的对象类型,是否可以被ModelLoader所处理
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;
}
3.8.6 DecodeHelp获取loadData传入startNextLoad方法:
List> getLoadData() {
if (!isLoadDataSet) {
isLoadDataSet = true;
loadData.clear();
//从Glide注册的register中获取modelLoaders
List> modelLoaders = glideContext.getRegistry().getModelLoaders(model);
//遍历modelLoaders
for (int i = 0, size = modelLoaders.size(); i < size; i++) {
//此时的model为url的string格式,返回该其中一个实现类为StringLoader
ModelLoader
3.8.7 startNextLoad()
继续查看 startNextLoad()方法接着通过LoadData对象内部的 fetcher ,来进行实际的请求操作(例如发起网络请求)
private void startNextLoad(final LoadData> toStart) {
loadData.fetcher.loadData(
helper.getPriority(),
new DataCallback
** 3.8.8 **
接着上面 loadData.fetcher.loadData逻辑,他是最终获取资源的,比如网络请求数据,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) {
callback.onLoadFailed(e);
} finally {
}
}
** 3.8.9 **
执行网络请求返回数据流
private InputStream loadDataWithRedirects(
URL url, int redirects, URL lastUrl, Map headers) throws IOException {
if (redirects >= MAXIMUM_REDIRECTS) {
throw new HttpException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!");
} else {
// Comparing the URLs using .equals performs additional network I/O and is generally broken.
// See http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html.
try {
if (lastUrl != null && url.toURI().equals(lastUrl.toURI())) {
throw new HttpException("In re-direct loop");
}
} catch (URISyntaxException e) {
// Do nothing, this is best effort.
}
}
urlConnection = connectionFactory.build(url);
for (Map.Entry headerEntry : headers.entrySet()) {
urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
}
urlConnection.setConnectTimeout(timeout);
urlConnection.setReadTimeout(timeout);
urlConnection.setUseCaches(false);
urlConnection.setDoInput(true);
// Stop the urlConnection instance of HttpUrlConnection from following redirects so that
// redirects will be handled by recursive calls to this method, loadDataWithRedirects.
urlConnection.setInstanceFollowRedirects(false);
// Connect explicitly to avoid errors in decoders if connection fails.
urlConnection.connect();
// Set the stream so that it's closed in cleanup to avoid resource leaks. See #2352.
stream = urlConnection.getInputStream();
if (isCancelled) {
return null;
}
final int statusCode = urlConnection.getResponseCode();
if (isHttpOk(statusCode)) {
return getStreamForSuccessfulRequest(urlConnection);
} else if (isHttpRedirect(statusCode)) {
String redirectUrlString = urlConnection.getHeaderField("Location");
if (TextUtils.isEmpty(redirectUrlString)) {
throw new HttpException("Received empty or null redirect url");
}
URL redirectUrl = new URL(url, redirectUrlString);
// Closing the stream specifically is required to avoid leaking ResponseBodys in addition
// to disconnecting the url connection below. See #2352.
cleanup();
return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
} else if (statusCode == INVALID_STATUS_CODE) {
throw new HttpException(statusCode);
} else {
throw new HttpException(urlConnection.getResponseMessage(), statusCode);
}
}
** 3.8.10 **
请求数据成功后, callback.onDataReady(result)在SourceGenerator的startNextLoad里面(3.8.7)接收回调数据,
private void startNextLoad(final LoadData> toStart) {
loadData.fetcher.loadData(
helper.getPriority(),
new DataCallback
**3.9 **
这时候数据已经请求到了,执行onDataReadyInternal方法,参数有loadDate和请求到的数据
@SuppressWarnings("WeakerAccess")
@Synthetic
void onDataReadyInternal(LoadData> loadData, Object data) {
DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
//如果该数据类型,有启用磁盘缓存,就把值赋给dataToCache
if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
dataToCache = data;
//调用DecodeJob的reschedule,用线程池执行任务,实际上就是再次调用SourceGenerator的startNext
cb.reschedule();
} else {
// 继续回调FetcherReadyCallback的onDataFetcherReady方法,将data回调出去
cb.onDataFetcherReady(
loadData.sourceKey,
data,
loadData.fetcher,
loadData.fetcher.getDataSource(),
originalKey);
}
}
3.9.1 解析数据
这个回调方法走的是DecodeJob.onDataFetcherReady(),DecodeJob类实现了FetcherReadyCallback接口。
然后解析数据
@Override
public void reschedule() {
runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
callback.reschedule(this);
}
@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();
}
}
}
3.9.2
DecodeJob.decodeFromRetrievedData
==解析得到资源==
private void decodeFromRetrievedData() {
Resource resource = null;
try {
// 从数据中解码得到资源
resource = decodeFromData(currentFetcher, currentData, currentDataSource);
} catch (GlideException e) {
...
}
// 最终得到的Resource对象,
if (resource != null) {
notifyEncodeAndRelease(resource, currentDataSource);
} else {
runGenerators();
}
}
至此:得到了网络请求的数据,并解析后得到了资源
3.9.3
看下怎么解析数据的
private Resource decodeFromData(
DataFetcher> fetcher, Data data, DataSource dataSource) throws GlideException {
try {
if (data == null) {
return null;
}
long startTime = LogTime.getLogTime();
//继续解析数据
Resource result = decodeFromFetcher(data, dataSource);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Decoded result " + result, startTime);
}
return result;
} finally {
fetcher.cleanup();
}
}
这里的data 是一个泛型,本例中是 Stream 流,从http请求获取到的
private Resource decodeFromFetcher(Data data, DataSource dataSource){
LoadPath path = decodeHelper.getLoadPath((Class) data.getClass());
//通过解析器来解析数据
return runLoadPath(data, dataSource, path);
}
上面代码看出:
1、获取一个LoadPath,它是根据数据类型(这里是stream),ResourceDecoder(资源解码),transcoder(资源转码)
2、从这些参数可以看出,最终把数据流转为Bitmap 或Drawable ,就是在LoadPath中进行的,这里是指DecodePath
private Resource runLoadPath(
Data data, DataSource dataSource, LoadPath path)
throws GlideException {
Options options = getOptionsWithHardwareConfig(dataSource);
//此时的data为InputStream对象,故rewinder为InputStreamRewinder对象
DataRewinder rewinder = glideContext.getRegistry().getRewinder(data);
try {
//执行LoadPath 的load ,进行解码,转换操作
return path.load(
rewinder, options, width, height, new DecodeCallback(dataSource));
} finally {
rewinder.cleanup();
}
}
3.9.4
LoadPath.load() 解析数据
public Resource load(
{
...参数省略...
return loadWithExceptionList(rewinder, options, width, height, decodeCallback, throwables);
} finally {
listPool.release(throwables);
}
}
重点在下面方法:正真的解码
private Resource loadWithExceptionList(
DataRewinder rewinder,
@NonNull Options options,
int width,
int height,
DecodePath.DecodeCallback decodeCallback,
List exceptions)
throws GlideException {
Resource result = null;
//遍历DecodePath集合
for (int i = 0, size = decodePaths.size(); i < size; i++) {
DecodePath path = decodePaths.get(i);
try {
//重点:调用DecodePath.decode真正进行数据解析
result = path.decode(rewinder, width, height, options, decodeCallback);
} catch (GlideException e) {
exceptions.add(e);
}
if (result != null) {
break;
}
}
if (result == null) {
throw new GlideException(failureMessage, new ArrayList<>(exceptions));
}
return result;
}
解码逻辑:
public Resource decode(
DataRewinder rewinder,
int width,
int height,
@NonNull Options options,
DecodeCallback callback)
throws GlideException {
//获取到Resource对象
Resource decoded = decodeResource(rewinder, width, height, options);
// 这个方法是回调到Decodejob.onResourceDecoded ,作用是调用RequestOptions中的Transform处理图片,然后将ResourceCache的Key和Encode准备好(放在变量 deferEncoderManager中),最后将这个源数据进行写入磁盘缓存。
//这就是磁盘的源数据缓存。
Resource transformed = callback.onResourceDecoded(decoded);
//进行数据类型的转换
return transcoder.transcode(transformed, options);
}
@NonNull
private Resource decodeResource(
DataRewinder rewinder, int width, int height, @NonNull Options options)
throws GlideException {
List exceptions = Preconditions.checkNotNull(listPool.acquire());
try {
return decodeResourceWithList(rewinder, width, height, options, exceptions);
} finally {
listPool.release(exceptions);
}
}
3.9.5
继续decodeResourceWithList方法:decoder是一个ResourceDecoder接口(资源解码器),根据不同的DataType和ResourceType它会有不同的实现类,这里的实现类是ByteBufferBitmapDecoder
private Resource decodeResourceWithList(
DataRewinder rewinder,
int width,
int height,
@NonNull Options options,
List exceptions)
throws GlideException {
Resource result = null;
//noinspection ForLoopReplaceableByForEach to improve perf
for (int i = 0, size = decoders.size(); i < size; i++) {
ResourceDecoder decoder = decoders.get(i);
try {
DataType data = rewinder.rewindAndGet();
if (decoder.handles(data, options)) {
data = rewinder.rewindAndGet();
//根据DataType和ResourceType的类型分发给不同的解码器Decoder
result = decoder.decode(data, width, height, options);
}
} catch (IOException | RuntimeException |
}
return result;
}
3.9.6
ByteBufferBitmapDecoder的decode方法,
里面有个downsampler类,downsampler主要是对流进行解码,旋转,压缩,圆角等处理
public class ByteBufferBitmapDecoder implements ResourceDecoder {
private final Downsampler downsampler;
public ByteBufferBitmapDecoder(Downsampler downsampler) {
this.downsampler = downsampler;
}
@Override
public boolean handles(@NonNull ByteBuffer source, @NonNull Options options) {
return downsampler.handles(source);
}
@Override
public Resource decode(
@NonNull ByteBuffer source, int width, int height, @NonNull Options options)
throws IOException {
InputStream is = ByteBufferUtil.toStream(source);
//downsampler主要是对流进行解码,旋转,压缩,圆角等处理
return downsampler.decode(is, width, height, options);
}
}
3.9.7
继续DownSampler中的decode方法,省去多次跳转:
private Resource decode(
ImageReader imageReader,
int requestedWidth,
int requestedHeight,
Options options,
DecodeCallbacks callbacks)
throws IOException {
byte[] bytesForOptions = byteArrayPool.get(ArrayPool.STANDARD_BUFFER_SIZE_BYTES, byte[].class);
BitmapFactory.Options bitmapFactoryOptions = getDefaultOptions();
bitmapFactoryOptions.inTempStorage = bytesForOptions;
DecodeFormat decodeFormat = options.get(DECODE_FORMAT);
PreferredColorSpace preferredColorSpace = options.get(PREFERRED_COLOR_SPACE);
DownsampleStrategy downsampleStrategy = options.get(DownsampleStrategy.OPTION);
boolean fixBitmapToRequestedDimensions = options.get(FIX_BITMAP_SIZE_TO_REQUESTED_DIMENSIONS);
boolean isHardwareConfigAllowed =
options.get(ALLOW_HARDWARE_CONFIG) != null && options.get(ALLOW_HARDWARE_CONFIG);
try {
//得到解析后的bitmap
Bitmap result =
decodeFromWrappedStreams(
imageReader,
bitmapFactoryOptions,
downsampleStrategy,
decodeFormat,
preferredColorSpace,
isHardwareConfigAllowed,
requestedWidth,
requestedHeight,
fixBitmapToRequestedDimensions,
callbacks);
//把bitmap 封装进Resource ,返回Resource 对象
return BitmapResource.obtain(result, bitmapPool);
} finally {
releaseOptions(bitmapFactoryOptions);
byteArrayPool.put(bytesForOptions);
}
}
3.9.8 DownSampler.decodeFromWrappedStreams()
下面进入到decodeFromWrappedStreams 来看一下,这里涉及到bitmap在bitmapPool中的复用(==图片复用仅支持大小相同的位图==),目的是 如果bitmapPool 有可用的bitmap,就复用该bitmap。避免为Bitmap 分配内存,导致内存抖动
private Bitmap decodeFromWrappedStreams(
ImageReader imageReader,
BitmapFactory.Options options,
DownsampleStrategy downsampleStrategy,
DecodeFormat decodeFormat,
PreferredColorSpace preferredColorSpace,
boolean isHardwareConfigAllowed,
int requestedWidth,
int requestedHeight,
boolean fixBitmapToRequestedDimensions,
DecodeCallbacks callbacks)
throws IOException {
long startTime = LogTime.getLogTime();
int[] sourceDimensions = getDimensions(imageReader, options, callbacks, bitmapPool);
int sourceWidth = sourceDimensions[0];
int sourceHeight = sourceDimensions[1];
String sourceMimeType = options.outMimeType;
if (sourceWidth == -1 || sourceHeight == -1) {
isHardwareConfigAllowed = false;
}
int orientation = imageReader.getImageOrientation();
int degreesToRotate = TransformationUtils.getExifOrientationDegrees(orientation);
boolean isExifOrientationRequired = TransformationUtils.isExifOrientationRequired(orientation);
int targetWidth =
requestedWidth == Target.SIZE_ORIGINAL
? (isRotationRequired(degreesToRotate) ? sourceHeight : sourceWidth)
: requestedWidth;
int targetHeight =
requestedHeight == Target.SIZE_ORIGINAL
? (isRotationRequired(degreesToRotate) ? sourceWidth : sourceHeight)
: requestedHeight;
ImageType imageType = imageReader.getImageType();
//计算缩放比例,结果会体现在options参数中
calculateScaling(
imageType,
imageReader,
callbacks,
bitmapPool,
downsampleStrategy,
degreesToRotate,
sourceWidth,
sourceHeight,
targetWidth,
targetHeight,
options);
calculateConfig(
imageReader,
decodeFormat,
isHardwareConfigAllowed,
isExifOrientationRequired,
options,
targetWidth,
targetHeight);
//计算sdk版本是否大于KITKAT,在该系统及之前 图片复用仅支持大小相同的位图
boolean isKitKatOrGreater = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// Prior to KitKat, the inBitmap size must exactly match the size of the bitmap we're decoding.
//下面的判断,来计算是否在BitmapPool中 是否有bitmap可以被复用,如果有就把bitmap 设置到options.inBitmap,
//这样在根据options 去解析生成bitmap的时候,就不需要再次分配内存了,
if ((options.inSampleSize == 1 || isKitKatOrGreater) && shouldUsePool(imageType)) {
int expectedWidth;
int expectedHeight;
if (sourceWidth >= 0
&& sourceHeight >= 0
&& fixBitmapToRequestedDimensions
&& isKitKatOrGreater) {
expectedWidth = targetWidth;
expectedHeight = targetHeight;
} else {
float densityMultiplier =
isScaling(options) ? (float) options.inTargetDensity / options.inDensity : 1f;
int sampleSize = options.inSampleSize;
int downsampledWidth = (int) Math.ceil(sourceWidth / (float) sampleSize);
int downsampledHeight = (int) Math.ceil(sourceHeight / (float) sampleSize);
expectedWidth = Math.round(downsampledWidth * densityMultiplier);
expectedHeight = Math.round(downsampledHeight * densityMultiplier);
if (expectedWidth > 0 && expectedHeight > 0) {
//该函数会在bitmapPool中查找符合大小的bitmap ,如果找到了就设置给inBitmap
setInBitmap(options, bitmapPool, expectedWidth, expectedHeight);
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
boolean isP3Eligible =
preferredColorSpace == PreferredColorSpace.DISPLAY_P3
&& options.outColorSpace != null
&& options.outColorSpace.isWideGamut();
options.inPreferredColorSpace =
ColorSpace.get(isP3Eligible ? ColorSpace.Named.DISPLAY_P3 : ColorSpace.Named.SRGB);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
options.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
}
//根据options 把流解析为Bitmap
Bitmap downsampled = decodeStream(imageReader, options, callbacks, bitmapPool);
callbacks.onDecodeComplete(bitmapPool, downsampled);
Bitmap rotated = null;
if (downsampled != null) {
downsampled.setDensity(displayMetrics.densityDpi);
rotated = TransformationUtils.rotateImageExif(bitmapPool, downsampled, orientation);
if (!downsampled.equals(rotated)) {
bitmapPool.put(downsampled);
}
}
//rotated就是最后解析后的bitmap。
return rotated;
}
至此已经得到了解析后的资源了,接下来就是要显示到指定的ImageView控件上.
4.1
接下来就是==将怎样将bitmap显示到控件的逻辑了。==
DecodeJob.decodeFromRetrievedData()
回到DecodeJob的decodeFromRetrievedData方法,解码后的resource不等于null时,调用notifyEncodeAndRelease方法:
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();
}
}
4.2
DecodeJob.notifyEncodeAndRelease
缓存资源,通知主线程显示
private void notifyEncodeAndRelease(Resource resource, DataSource dataSource) {
if (resource instanceof Initializable) {
((Initializable) resource).initialize();
}
Resource result = resource;
LockedResource lockedResource = null;
if (deferredEncodeManager.hasResourceToEncode()) {
lockedResource = LockedResource.obtain(resource);
result = lockedResource;
}
// 通知主线程回调,加载图片
notifyComplete(result, dataSource);
// 更新状态为编码
stage = Stage.ENCODE;
try {
if (deferredEncodeManager.hasResourceToEncode()) {
//将转码好的资源缓存到磁盘,这就是磁盘的额资源缓存。
deferredEncodeManager.encode(diskCacheProvider, options);
}
} finally {
if (lockedResource != null) {
lockedResource.unlock();
}
}
onEncodeComplete();
}
4.2.1 执行DecodeJob.notifyComplete() 将resourse回调到 EngineJob的onResourceReady()
private void notifyComplete(Resource resource, DataSource dataSource) {
setNotifiedOrThrow();
//这个callback 就是 EngineJob对象,是在创建Decodejob的时候传递进来
callback.onResourceReady(resource, dataSource);
}
4.3 EngineJob.onResourceReady()
接下来看EngineJob中onResourceReady方法:
@Override
public void onResourceReady(Resource resource, DataSource dataSource) {
synchronized (this) {
this.resource = resource;
this.dataSource = dataSource;
}
notifyCallbacksOfResult();
}
4.4 EngineJob.notifyCallbacksOfResult()
public void notifyCallbacksOfResult() {
ResourceCallbacksAndExecutors copy;
Key localKey;
EngineResource> localResource;
synchronized (this) {
stateVerifier.throwIfRecycled();
...
engineResource = engineResourceFactory.build(resource, isCacheable, key, resourceListener);
hasResource = true;
copy = cbs.copy();
incrementPendingCallbacks(copy.size() + 1);
localKey = key;
localResource = engineResource;
}
//这里就是把解析后的图片,也就是即将要显示出来的图片,缓存到弱引用缓存中
engineJobListener.onEngineJobComplete(this, localKey, localResource);
for (final ResourceCallbackAndExecutor entry : copy) {
//遍历每一个回调接口,entry.cb 就是SingleRequest 对象,执行接口ResourceCallback的run方法
entry.executor.execute(new CallResourceReady(entry.cb));
}
decrementPendingCallbacks();
}
看下CallResourceReady接口,定义在EngineJob中:
private class CallResourceReady implements Runnable {
private final ResourceCallback cb;
CallResourceReady(ResourceCallback cb) {
this.cb = cb;
}
@Override
public void run() {
synchronized (cb.getLock()) {
synchronized (EngineJob.this) {
if (cbs.contains(cb)) {
engineResource.acquire();
//执行回调
callCallbackOnResourceReady(cb);
removeCallback(cb);
}
decrementPendingCallbacks();
}
}
}
}
void callCallbackOnResourceReady(ResourceCallback cb) {
try {
//cb 就是SingleRequest 对象,所以下面去它里面看onResourceReady
cb.onResourceReady(engineResource, dataSource);
} catch (Throwable t) {
throw new CallbackException(t);
}
}
SingleRequest对象的onResourceReady方法,他是ResourceCallback接口定义方法
public void onResourceReady(Resource> resource, DataSource dataSource) {
stateVerifier.throwIfRecycled();
Resource> toRelease = null;
...
onResourceReady((Resource) resource, (R) received, dataSource);
} finally {
if (toRelease != null) {
engine.release(toRelease);
}
}
}
private void onResourceReady(Resource resource, R result, DataSource dataSource) {
boolean isFirstResource = isFirstReadyResource();
status = Status.COMPLETE;
this.resource = resource;
isCallingCallbacks = true;
try {
...
if (!anyListenerHandledUpdatingTarget) {
Transition super R> animation = animationFactory.build(dataSource, isFirstResource);
//target 函数是在 buildTarget 时,创建的
target.onResourceReady(result, animation);
}
} finally {
isCallingCallbacks = false;
}
notifyLoadSuccess();
}
ImageViewTarget的onResourceReady方法,ImageViewTarget是一个抽象类,BitmapImageViewTarget继承它
@Override
public void onResourceReady(@NonNull Z resource, @Nullable Transition super Z> transition) {
if (transition == null || !transition.transition(resource, this)) {
setResourceInternal(resource);
} else {
maybeUpdateAnimatable(resource);
}
}
private void setResourceInternal(@Nullable Z resource) {
//抽象方法,执行不同的实现,我们是以BitmapImageViewTarget为例:
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);
}
BitmapImageViewTarget中显示资源,把图片设置到ImageView中
*/
@Override
protected void setResource(Bitmap resource) {
view.setImageBitmap(resource);
}
终于啃完了,比较费事,如果发现哪里有错误,烦请指出~~~加油,奥利盖~~~
至此,完结...