Glide现在应用最广的一个图片加载框架了,一直都想对它下手,每次都是深陷其中。。。这次狠下心来,对它来个全面的剖析,争取对整个流程和其中的细节都有一个覆盖。
本文的Glide的解析是基于最新的4.11.0版本来进行的。
其实从一般的网络加载图片,可以简单分析下大体的流程,无非就是建立相关的请求信息,然后通过线程池技术对请求信息进行请求,然后将下载的图片文件进行转化显示。
先来看个简单的测试使用代码开始,然后逐步深入
Glide.with(view.getContext()) .load(url) .into(view);
with()
Glide的with函数为我们提供了不同的入参,其最终的返回对象都是 RequestManager

我们的测试代码用的是 Context 那么这里我们就跟踪一下这个函数,其实其他几个都是相似的
@NonNull public static RequestManager with(@NonNull Context context) { return getRetriever(context).get(context); } @NonNull private static RequestManagerRetriever getRetriever(@Nullable Context context) { //校验Context不能为空 Preconditions.checkNotNull(context,"...."); return Glide.get(context).getRequestManagerRetriever(); } //直接获取Glide对象的requestManagerRetriever属性 public RequestManagerRetriever getRequestManagerRetriever() { return requestManagerRetriever; }
可以看到 RequestManagerRetriever 对象的创建,肯定是在 Glide.get() 中进行了处理
//通过双重加锁单例方法,创建Glide对象 public static Glide get(@NonNull Context context) { if (glide == null) { GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules(context.getApplicationContext()); synchronized (Glide.class) { if (glide == null) { checkAndInitializeGlide(context, annotationGeneratedModule); } } } return glide; } //校验并初始化Glide对象 @GuardedBy("Glide.class") private static void checkAndInitializeGlide( @NonNull Context context, @Nullable GeneratedAppGlideModule generatedAppGlideModule) { // 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, generatedAppGlideModule); isInitializing = false; } //初始化Glide @GuardedBy("Glide.class") private static void initializeGlide( @NonNull Context context, @Nullable GeneratedAppGlideModule generatedAppGlideModule) { initializeGlide(context, new GlideBuilder(), generatedAppGlideModule); } @GuardedBy("Glide.class") @SuppressWarnings("deprecation") private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder, @Nullable GeneratedAppGlideModule annotationGeneratedModule) { ... //创建了RequestManagerFactory工厂对象,用来创建对应的RequestManager RequestManagerRetriever.RequestManagerFactory factory = annotationGeneratedModule != null ? annotationGeneratedModule.getRequestManagerFactory() : null; builder.setRequestManagerFactory(factory); ... //建造者设计模式,创建Glide对象 Glide glide = builder.build(applicationContext); ... applicationContext.registerComponentCallbacks(glide); Glide.glide = glide; }
可以看到,这里使用建造者设计模式,来创建了 glide 对象。在 builder 中设置了一个 RequestManagerFactory 的属性。看下在builder中,具体帮我们做了什么工作。
@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) {//连接监控的工厂 connectivityMonitorFactory = new DefaultConnectivityMonitorFactory(); } if (bitmapPool == null) {//bitmap池 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) {//内存缓存策略,默认使用Lru缓存策略 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) {//请求监听器,是一个不可变的List defaultRequestListeners = Collections.emptyList(); } else { defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners); } //这里创建了一个RequestManagerRetriever对象,参数是之前设置的Factory对象 RequestManagerRetriever requestManagerRetriever = new RequestManagerRetriever(requestManagerFactory); return new Glide(//创建Glide对象 context, engine, memoryCache, bitmapPool, arrayPool, requestManagerRetriever, connectivityMonitorFactory, logLevel, defaultRequestOptionsFactory, defaultTransitionOptions, defaultRequestListeners, isLoggingRequestOriginsEnabled, isImageDecoderEnabledForBitmaps); }
在 GlideBuilder 中,帮我们创建了很多的对象,包括线程池、缓存器、缓存大小、Engine、RequestManagerRetriever。
因为我们在调用 with() 方法时,使用了 requestManagerRetriever ,我们这里去看一眼,里面有没有做什么特殊处理
public RequestManagerRetriever(@Nullable RequestManagerFactory factory) { this.factory = factory != null ? factory : DEFAULT_FACTORY; handler = new Handler(Looper.getMainLooper(), this /* Callback */); } 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); } };
很简单的构造函数,里面创建了 handler对象,并设置了 RequestManagerFactory 对象。
回到主干,看看Glide的构造函数。
Glide( @NonNull Context context, @NonNull Engine engine, @NonNull MemoryCache memoryCache, @NonNull BitmapPool bitmapPool, @NonNull ArrayPool arrayPool, @NonNull RequestManagerRetriever requestManagerRetriever, @NonNull ConnectivityMonitorFactory connectivityMonitorFactory, int logLevel, @NonNull RequestOptionsFactory defaultRequestOptionsFactory, @NonNull Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions, @NonNull List<RequestListener<Object>> defaultRequestListeners, boolean isLoggingRequestOriginsEnabled, boolean isImageDecoderEnabledForBitmaps) { this.engine = engine; this.bitmapPool = bitmapPool; this.arrayPool = arrayPool; this.memoryCache = memoryCache; this.requestManagerRetriever = requestManagerRetriever; this.connectivityMonitorFactory = connectivityMonitorFactory; this.defaultRequestOptionsFactory = defaultRequestOptionsFactory; final Resources resources = context.getResources(); //注册机,里面维护了编码、解码、加载、图片请求头、支持的图片等的各种注册表信息 registry = new Registry(); registry.register(new DefaultImageHeaderParser()); registry .append(int.class, InputStream.class, resourceLoaderStreamFactory) ....... ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory(); glideContext = new GlideContext(//创建glideContext对象 context, arrayPool, registry, imageViewTargetFactory, defaultRequestOptionsFactory, defaultTransitionOptions, defaultRequestListeners, engine, isLoggingRequestOriginsEnabled, logLevel); }
这里面将一些属性赋值,并且创建了 GlideContext 对象,以及registry对象。
到此为止,我们的Glide单例对象创建完成了....
RequestManger对象的获取
public static RequestManager with(@NonNull Context context) { return getRetriever(context).get(context); }
在获取到 RequestManagerRetriever 对象以后,通过 get 方法来获取到 RequestManager 对象,我们现在来跟踪一下代码的实现。
@NonNull public RequestManager get(@NonNull Context context) { if (context == null) {//context为空抛异常 throw new IllegalArgumentException("You cannot start a load on a null Context"); } else if (Util.isOnMainThread() && !(context instanceof Application)) { //如果当前线程是主线程,并且context不是Application,那么对应的生命周期是和UI(Activity或者Fragment)进行绑定的, //通过创建隐藏Fragment的方法来监听context的生命周期。然后将RequestManager和Fragment来绑定。 //因为v4和普通的Fragment中创建Fragment的方式是不同的,所以这里根据不同的context类型,来进行不同的处理 if (context instanceof FragmentActivity) {//如果是FragmentActivity return get((FragmentActivity) context); } else if (context instanceof Activity) {//如果是普通的Activity return get((Activity) context); } else if (context instanceof ContextWrapper // Only unwrap a ContextWrapper if the baseContext has a non-null application context. // Context#createPackageContext may return a Context without an Application instance, // in which case a ContextWrapper may be used to attach one. && ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) { return get(((ContextWrapper) context).getBaseContext()); } } //返回应用RequestManager return getApplicationManager(context); }
在get()方法中,根据Context的类型的不同,来进行了不同的处理。我们这里跟踪一个 FragmentActivity 类型的,其他的是相似的
@NonNull public RequestManager get(@NonNull FragmentActivity activity) { if (Util.isOnBackgroundThread()) {//如果是后台线程,则context按照application处理,即和UI的生命周期解绑 return get(activity.getApplicationContext()); } else { //在UI线程进行处理 assertNotDestroyed(activity);//判断activity是否被销毁了 FragmentManager fm = activity.getSupportFragmentManager(); return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity)); } } //获取FragmentManager所管理的RequestManager private RequestManager supportFragmentGet(@NonNull Context context, @NonNull FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) { //创建一个隐形的SupportRequestManagerFragment,来监听对应的Context的生命周期 SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint, isParentVisible); //获取Fragment中对应的请求管理器,(每个Fragment只有一个唯一的请求管理器) RequestManager requestManager = current.getRequestManager(); if (requestManager == null) {//如果当前没有设置过请求管理器,那么创建并设置 Glide glide = Glide.get(context); //通过工厂方法,创建requestManager对象 requestManager = factory.build(glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context); current.setRequestManager(requestManager); } return requestManager; }
实际的 RequestManager 是通过factory来构建的
RequestManager(Glide glide, Lifecycle lifecycle, RequestManagerTreeNode treeNode, RequestTracker requestTracker, ConnectivityMonitorFactory factory, Context context) { this.glide = glide; this.lifecycle = lifecycle; this.treeNode = treeNode; this.requestTracker = requestTracker; this.context = context; //连接监听器 connectivityMonitor = factory .build(context.getApplicationContext(), new RequestManagerConnectivityListener(requestTracker)); if (Util.isOnBackgroundThread()) { mainHandler.post(addSelfToLifecycle); } else { lifecycle.addListener(this); } lifecycle.addListener(connectivityMonitor); defaultRequestListeners = new CopyOnWriteArrayList<>(glide.getGlideContext().getDefaultRequestListeners()); //设置请求配置信息 setRequestOptions(glide.getGlideContext().getDefaultRequestOptions()); //将RequestManager注册到全局glide中 glide.registerRequestManager(this); }
到现在为止,我们已经对于创建了 RequestManager ,那么后续就是其调用 load() 方法了。
load()
RequestManager 支持对多种参数形式的图片加载:

我们从我们的案例跟踪,传入的参数是String类型。
//相当于先调用了asDrawable(),然后调用了load()方法 public RequestBuilder<Drawable> load(@RawRes @DrawableRes @Nullable Integer resourceId) { return asDrawable().load(resourceId); } public RequestBuilder<Drawable> asDrawable() { return as(Drawable.class); } //创建能够解码对应类型的图片的RequestBuilder public <ResourceType> RequestBuilder<ResourceType> as( @NonNull Class<ResourceType> resourceClass) { return new RequestBuilder<>(glide, this, resourceClass, context); }
我们看下 RequestBuilder 的构造方法做了什么处理
protected RequestBuilder(@NonNull Glide glide, RequestManager requestManager, Class<TranscodeType> transcodeClass, Context context) { this.glide = glide; this.requestManager = requestManager; this.transcodeClass = transcodeClass; this.context = context; //这里的transcodeClass大概率是Drawable类对象 this.transitionOptions = requestManager.getDefaultTransitionOptions(transcodeClass); this.glideContext = glide.getGlideContext(); initRequestListeners(requestManager.getDefaultRequestListeners()); apply(requestManager.getDefaultRequestOptions()); }
在创建完RequestBuilder对象之后,直接调用了 RequestBuilder 的 load() 方法。
public RequestBuilder<TranscodeType> load(@Nullable String string) { return loadGeneric(string); } private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) { this.model = model; isModelSet = true; return this; }
这里也没有进行特殊的操作,只是将 isModelSet 设置为了true,标记model已经进行了设置。
into()
在 with() 和 load() 方法中,主要是进行了一些前期的准备工作。真正执行图片的加载、缓存、转化到View上等等这些操作,都是在 into() 中执行的。
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) { Util.assertMainThread();//方法需要在主线程执行 Preconditions.checkNotNull(view);//view不能为空 BaseRequestOptions<?> requestOptions = this; if (!requestOptions.isTransformationSet() && requestOptions.isTransformationAllowed() && view.getScaleType() != null) {//根据View上配置的scaleType,设置requestOptions switch (view.getScaleType()) { case CENTER_CROP: requestOptions = requestOptions.clone().optionalCenterCrop(); break; } } return into(glideContext.buildImageViewTarget(view, transcodeClass),/*targetListener=*/ null, requestOptions, Executors.mainThreadExecutor()); }
这里根据设置的信息配置 requestOptions 相关参数,然后调用了 buildImageViewTarget 方法,构造了一个 viewTarget 对象。
我们现在看一下这个方法
@NonNull public <X> ViewTarget<ImageView, X> buildImageViewTarget( @NonNull ImageView imageView, @NonNull Class<X> transcodeClass) { //通过工厂方法创建ViewTarget对象,这里一般返回的是DrawableImageViewTarget,如果是使用了asBitmap那么返回的是BitmapImageViewTarget return imageViewTargetFactory.buildTarget(imageView, transcodeClass); } public class ImageViewTargetFactory { public <Z> ViewTarget<ImageView, Z> buildTarget( @NonNull ImageView view, @NonNull Class<Z> clazz) { if (Bitmap.class.equals(clazz)) {//如果使用了asBitmap方法,那么这里的clazz回事bitmap return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view); } else if (Drawable.class.isAssignableFrom(clazz)) {//如果只是正常的使用,一般会返回DrawableImageViewTarget return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view); } else { throw new IllegalArgumentException("Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)"); } } }
可以看到这里,大部分情况下返回的是一个 DrawableImageViewTarget 对象信息,
回到主线。继续
private <Y extends Target<TranscodeType>> Y into(@NonNull Y target, @Nullable RequestListener<TranscodeType> targetListener, BaseRequestOptions<?> options, Executor callbackExecutor) { Preconditions.checkNotNull(target); if (!isModelSet) {//如果model没有进行设置(没有调用load方法会导致这种情况的方法),直接报错。 throw new IllegalArgumentException("You must call #load() before calling #into()"); } //创建一个request请求 Request request = buildRequest(target, targetListener, options, callbackExecutor); //获取target上是否已经存在了相应的请求,如果存在,则进行清空处理 Request previous = target.getRequest(); if (request.isEquivalentTo(previous) && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) { //target上标记点的请求和生成的请求相同,直接启动相应的请求,然后返回target对象 if (!Preconditions.checkNotNull(previous).isRunning()) { previous.begin(); } return target; } //将原有的target从请求管理类requestManager中移除掉 requestManager.clear(target); //将新的请求设置进target target.setRequest(request); //requestManager开启对于target和request的跟踪处理(主要是启动请求,并且将请求类和target进行统一管理) requestManager.track(target, request); return target; }
这段代码是Glide的核心,里面进行了 Request 请求对象的创建以及执行。
请求对象的创建过程
我们先看下 Request 请求对象的创建过程: buildRequest()
private Request buildRequest(Target<TranscodeType> target, @Nullable RequestListener<TranscodeType> 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<TranscodeType> target, @Nullable RequestListener<TranscodeType> 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); ... return errorRequestCoordinator; }
这个函数将请求进行了分类,一种是错误显示的请求信息,一种是正常显示的请求信息。
我们看一下正常显示的请求处理函数中,是如何创建的。
//生成处理正常显示的请求,会根据相关的设置,创建缩略图或者原图 private Request buildThumbnailRequestRecursive(Object requestLock,Target<TranscodeType> target, RequestListener<TranscodeType> targetListener,@Nullable RequestCoordinator parentCoordinator, TransitionOptions<?, ? super TranscodeType> transitionOptions,Priority priority, int overrideWidth,int overrideHeight,BaseRequestOptions<?> requestOptions,Executor callbackExecutor) { if (thumbnailBuilder != null) {//存在缩略图生成器,根据builder信息创建缩略图请求 ... } else if (thumbSizeMultiplier != null) {//存在图片放大缩小指数,则根据指数信息创建缩略图请求 ... } else { //一般会通过这个方法进行处理 return obtainRequest(requestLock, target, targetListener, requestOptions, parentCoordinator, transitionOptions, priority, overrideWidth, overrideHeight, callbackExecutor); } }
这个代码段很长,我们进行了省略,里面大部分都是对于生成缩略图请求的一些特殊处理。后面我们有机会再分析。我们主要看一下 obtainRequest 这个方法是如何来创建标准请求的。
private Request obtainRequest(Object requestLock, Target<TranscodeType> target, RequestListener<TranscodeType> targetListener, BaseRequestOptions<?> requestOptions, RequestCoordinator requestCoordinator, TransitionOptions<?, ? super TranscodeType> transitionOptions, Priority priority, int overrideWidth, int overrideHeight, Executor callbackExecutor) { return SingleRequest.obtain(context, glideContext, requestLock, model, transcodeClass, requestOptions, overrideWidth, overrideHeight, priority, target, targetListener, requestListeners, requestCoordinator, glideContext.getEngine(), transitionOptions.getTransitionFactory(), callbackExecutor); }
这个方法继续跟踪,可以发现只是创建了一个 SingleRequest 对象,并且把相关参数进行了赋值,里面并没有什么特殊的处理。
到此为止,我们的 Request 已经创建完成了。下一步就是看一下,是如何进行网络请求的。
请求的执行
回到原来的 into() 代码块中,这次我们跟踪的是 requestManager.track(target, request) 这个函数
synchronized void track(@NonNull Target<?> target, @NonNull Request request) { //target管理类,里面通过set列表方式保存了所有的target信息,并且实现了生命周期接口,能够根据生命周期,启动或者暂停target的动画 targetTracker.track(target); //requestTracker管理类,里面通过set列表方式保存了所有的request信息,通过runRequest方法,将请求保存到set列表,并启动请求 requestTracker.runRequest(request); } //启动并跟踪请求 public void runRequest(@NonNull Request request) { requests.add(request);//保存到set列表 if (!isPaused) {//加载处于可用状态,直接调用begin() request.begin(); } else {//加载处于暂停状态,将request请求保存起来的,等可以状态时,从列表里面逐个启动 request.clear(); if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "Paused, delaying request"); } //将请求放到pendingRequests,因为requests是弱引用,防止被回收 pendingRequests.add(request); } }
这里就是个简单的处理,如果当前的 RequestManager 处于可用状态(即绑定的Context是处于可见的),那么就直接进行任务的请求处理。否则将请求放到 pendingRequests 所对应的的set列表中,虽然 requests中已经保存了对应的请求信息,但是由于其是弱引用,所以存在会被回收的情况,所以使用了pendingRequests来进行保存。
在创建请求对象的分析中,我们知道最后创建的是 SingleRequest 对象,继续 begin() 方法的跟踪
public void begin() { synchronized (requestLock) { assertNotCallingCallbacks(); stateVerifier.throwIfRecycled(); startTime = LogTime.getLogTime(); if (model == null) {//如果加载的图片源(url,file等)为null,则直接onLoadFailed ... onLoadFailed(new GlideException("Received null model"), logLevel); return; } if (status == Status.RUNNING) {//如果请求正在进行,则直接抛异常 throw new IllegalArgumentException("Cannot restart a running request"); } if (status == Status.COMPLETE) {//如果请求已经完成,则直接调用onResourceReady接口 //如果我们重新启动后完成(通常是通过一个notifyDataSetChanged将一个相同的请求开始到相同的目标或视图), //我们可以简单地使用资源和大小,而不需要获得一个新的尺寸,开始一个新的加载等。 // 这确实意味着,如果客户确实需要重新加载,那么需要在加载之前,显示的调用clear清除视图或目标。 onResourceReady(resource, DataSource.MEMORY_CACHE); return; } status = Status.WAITING_FOR_SIZE; if (Util.isValidDimensions(overrideWidth, overrideHeight)) { //如果要加载的视图的宽和高已经固定,直接进行加载 onSizeReady(overrideWidth, overrideHeight); } else { //设置回调信息,当视图的宽高完成以后,进行回调处理。通过target(Target类,里面包含要了View的信息)的getViewTreeObserver方法,来监听控件的绘制,从而能够获取到对应的宽高,最后通过接口回调调用onSizeReady(width,height)方法 target.getSize(this); } if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE) && canNotifyStatusChanged()) { //设置PlaceholderDrawable这些信息,然后去后台加载资源,最后将对应的数据显示在target上面 target.onLoadStarted(getPlaceholderDrawable()); } if (IS_VERBOSE_LOGGABLE) { logV("finished run method in " + LogTime.getElapsedMillis(startTime)); } } }
在 begin() 函数中最主要的是通过View宽高已知(不论是已经固定还是通过绘制后的回调)的情况下,调用 onSizeReady 方法来执行具体的加载过程。而且在加载未完成的情况下,在View上设置了对应的占位图(也就是我们经常在代码里面使用的 .placeholder() 方法)。
public void onSizeReady(int width, int height) { stateVerifier.throwIfRecycled(); synchronized (requestLock) { ... float sizeMultiplier = requestOptions.getSizeMultiplier();//根据缩放比例来进行宽高的重新处理 this.width = maybeApplySizeMultiplier(width, sizeMultiplier); this.height = maybeApplySizeMultiplier(height, sizeMultiplier); ... 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); ... } }
函数最终是通过调用了 engine.load 来执行的加载过程。
//真正的加载,通过多级缓存来进行处理 public <R> LoadStatus load( GlideContext glideContext, Object model, Key signature, int width, int height, Class<?> resourceClass, Class<R> transcodeClass, Priority priority, DiskCacheStrategy diskCacheStrategy, Map<Class<?>, Transformation<?>> transformations, boolean isTransformationRequired, boolean isScaleOnlyOrNoTransform, Options options, boolean isMemoryCacheable, boolean useUnlimitedSourceExecutorPool, boolean useAnimationPool, boolean onlyRetrieveFromCache, ResourceCallback cb, Executor callbackExecutor) { long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0; EngineKey key = keyFactory.buildKey(//根据相关参数创建一个key值 model, signature, width, height, transformations, resourceClass, transcodeClass, options); EngineResource<?> memoryResource; synchronized (this) { //从内存加载 memoryResource = loadFromMemory(key, isMemoryCacheable, startTime); if (memoryResource == null) { //如果在内存中没有查询到,那么内部创建一个Job并进行执行,返回LoadStatus return waitForExistingOrStartNewJob( glideContext, model, signature, width, height, resourceClass, transcodeClass, priority, diskCacheStrategy, transformations, isTransformationRequired, isScaleOnlyOrNoTransform, options, isMemoryCacheable, useUnlimitedSourceExecutorPool, useAnimationPool, onlyRetrieveFromCache, cb, callbackExecutor, key, startTime); } }
我们都知道,现有的任何一个图片加载框架都使用了缓存来进行数据的处理,以此来加快图片的加载速度。Glide 也不例外,从代码可以看到对于资源的加载。
通过相关的参数生成了一个key
- 通过key在内存查找
- 如果查找到了,那么直接通过接口回调来返回资源信息。
- 如果没有,则会创建新的任务请求来加载。
我们先从内存加载函数 loadFromMemory() 来分析一下是如何处理的。
private EngineResource<?> loadFromMemory(EngineKey key, boolean isMemoryCacheable, long startTime) { if (!isMemoryCacheable) {//如果不允许在缓存加载,直接返回 通过.skipMemoryCache(false)来关闭缓存功能 return null; } //从正在使用的图片列表中获取 EngineResource<?> active = loadFromActiveResources(key); if (active != null) { return active; } //从MemoryCache(这里使用的一般是LurMemoryCache)中获取 EngineResource<?> cached = loadFromCache(key); if (cached != null) { return cached; } return null; } //从正在使用的资源中加载的 private EngineResource<?> loadFromActiveResources(Key key) { //从已经被加载的资源中获取 EngineResource<?> active = activeResources.get(key); if (active != null) {//占用资源的计数器+1 active.acquire(); } return active; } //从cache中获取 private EngineResource<?> loadFromCache(Key key) { //从Cache中获取 EngineResource<?> cached = getEngineResourceFromCache(key); if (cached != null) { //如果缓存中存在,则从缓存中移除,并放入到正在使用的Resource列表中 cached.acquire(); activeResources.activate(key, cached); } return cached; }
源码相对来说比较简单。
- loadFromActiveResources() 先从正在使用的资源中去查找。如果查找到,将资源的引用计数器+1,返回资源文件。
- 如果没有查找到,则从缓存中获取,缓存默认使用的LruMemoryCache(可以使用)。如果获取成功,则从缓存中移除,并放置到activeResources中(强引用)。防止缓存被回收导致的资源失效。
- 如果仍然没有,则整个函数返回null
如果最终没有从内存获取到资源文件,那么代码会通过 waitForExistingOrStartNewJob 来执行资源的加载。
//使用已有的Job或者创建新的Job来进行资源加载 private <R> LoadStatus waitForExistingOrStartNewJob(...) { //从在执行的jobs列表中查询,onlyRetrieveFromCache为仅从缓存加载图片标志位。 EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache); if (current != null) { //如果存在,则为当前任务增加一个回调接口, //可能一个资源在多个地方同时使用的情况,因此,加载完成后,需要回调多个接口来进行通知 current.addCallback(cb, callbackExecutor); return new LoadStatus(cb, current); } //创建一个EngineJob EngineJob<R> engineJob =engineJobFactory.build(...); //负责从缓存的数据资源或者原始资源获取数据,是数据的获取类 DecodeJob<R> decodeJob =decodeJobFactory.build(...); //将engineJob存放到jobs,engineJob中有onlyRetrieveFromCache的字段,所以可以根据该字段放置到不同的list中 jobs.put(key, engineJob); //增加回调接口 engineJob.addCallback(cb, callbackExecutor); //启动engineJob去加载资源 engineJob.start(decodeJob); return new LoadStatus(cb, engineJob); }
我们这里只关心新建 EngineJob 并执行加载的过程,所以这里我们主要看一下 engineJob.start(decodeJob) 的执行
public synchronized void start(DecodeJob<R> decodeJob) { this.decodeJob = decodeJob; //根据decodeJob的设置,使用不存的执行器 GlideExecutor executor = decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor(); //启动decodeJob,decodeJob实现了Runnable接口,会调用其run()方法 executor.execute(decodeJob); }
我们现在看看DecodeJob的run方法
@Override public void run() { DataFetcher<?> localFetcher = currentFetcher; try { if (isCancelled) {//如果已经取消了,则直接返回失败。isCancelled是volatile。保证了多线程的可见性 notifyFailed();//通知上层(EngineJob)调用失败,并且进行相关资源的回收工作 return; } //主要的加载函数 runWrapped(); } catch (CallbackException e) { //如果已经进入了encode阶段时,我们已经调用了callback上层接口,这时候需要通过调用失败接口来进行资源释放,否则是不安全的 // 可以查看notifyEncodeAndRelease(Resource, DataSource)方法里面 if (stage != Stage.ENCODE) { throwables.add(t); notifyFailed(); } throw t; } finally { if (localFetcher != null) {//进行localFetcher的清理工作,因为DecodeJob是进行复用的。 localFetcher.cleanup(); } GlideTrace.endSection();//记录整个Glide的跟踪记录信息 } }
run 方法只有一个最主要的函数,就是 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); } } //数据资源获取生成器, 初始化->资源缓存解码->数据缓存->源->结束 // 根据不同的阶段,生成不同的数据加载器 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); } } /** * 根据当前状态,返回下一个状态。由于diskCacheStrategy默认的使用AUTOMATIC的缓存策略, * decodeCachedResource()和decodeCachedData()返回的都是true * 下一个阶段图: * 初始化->资源缓存解码->数据缓存->源->结束 * */ 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: return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE; case SOURCE: case FINISHED: return Stage.FINISHED; default: throw new IllegalArgumentException("Unrecognized stage: " + current); } }
Glide的资源加载的主要流程依次为
- 资源缓存解码
- 数据缓存
- 数据源源
其对应的数据加载类为:
- ResourceCacheGenerator :从缓存文件加载数据(包括了向下采样/转化后的资源)
- DataCacheGenerator :从数据缓存加载数据(原始的缓存资源)
- SourceGenerator :从资源的源地址加载数据
根据用户的实际配置信息,可能会跳过中间的某一个或者多个步骤。
在创建了数据加载类以后,通过 *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; } } if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {//如果已经结束或者取消了,直接回调失败 notifyFailed(); } }
在该函数里面,通过while循环来遍历执行相关的数据加载器,直到所有的数据加载器都执行完,或者某个加载器加载到了相关的数据。
ResourceCacheGenerator#startNext
我们先看看 ResourceCacheGenerator 是如何执行加载过程的。
public boolean startNext() { //每种model都对应着多个解析器,最后根据model的格式(String,Uri等),来找到可以使用的LoadData列表。每个LoadData都会存在一个对应的key。 //这里获取了对应的key列表 List<Key> sourceIds = helper.getCacheKeys();//如果model没有对应的映射出来的key。则直接返回false if (sourceIds.isEmpty()) { return false; } //获取由model转化为resource的类,也即是可以decode的资源类信息 List<Class<?>> resourceClasses = helper.getRegisteredResourceClasses(); if (resourceClasses.isEmpty()) { if (File.class.equals(helper.getTranscodeClass())) { return false; } throw new IllegalStateException( "Failed to find any load path from " + helper.getModelClass() + " to " + helper.getTranscodeClass()); } while (modelLoaders == null || !hasNextModelLoader()) {//双层遍历 resourceClassIndex++; if (resourceClassIndex >= resourceClasses.size()) { sourceIdIndex++; if (sourceIdIndex >= sourceIds.size()) { return false; } resourceClassIndex = 0; } Key sourceId = sourceIds.get(sourceIdIndex); Class<?> resourceClass = resourceClasses.get(resourceClassIndex); Transformation<?> transformation = helper.getTransformation(resourceClass);se. currentKey = new ResourceCacheKey( // NOPMD Avoid Instantiating Objects InLoops helper.getArrayPool(), sourceId, helper.getSignature(), helper.getWidth(), helper.getHeight(), transformation, resourceClass, helper.getOptions()); //根据当前的key获取缓存的文件 cacheFile = helper.getDiskCache().get(currentKey); if (cacheFile != null) {//获取到缓存文件了,设置对应的modelLoader和key,而且会跳出循环 sourceKey = sourceId; modelLoaders = helper.getModelLoaders(cacheFile); modelLoaderIndex = 0; } } loadData = null; boolean started = false; while (!started && hasNextModelLoader()) { ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++); loadData = modelLoader.buildLoadData(cacheFile, helper.getWidth(), helper.getHeight(), helper.getOptions()); if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) { //有对应的LoadData started = true; //通过fetcher去加载对应的文件 loadData.fetcher.loadData(helper.getPriority(), this); } } return started; }
我们总结一下大体的流程:
- 根据传入的参数,获取对应的 sourceIds 和 resourceClasses
- 正交遍历,迭代每一组。根据相关参数生成在缓存文件使用的key,然后根据key去查询是否有缓存文件
- 如果查找到对应的缓存文件,则设置sourceKey 和modelLoaders。然后通过这两个的设置可以跳出循环。
- modeLoaders 遍历,获取 modelLoader ,并创建对应的 loadData 。
- 如果 LoadData 存在,并且其内部的 dataFatcher (数据读取器)获取的数据类存在,则设置started标志位,表明该从 ResourceCacheGenerator 已经加载到相关数据了(这样后面所有的加载器都不再执行)。然后通过dataFatcher去获取数据。
- 如果遍历没有加载相关数据,则返回started标志位为false。表明 ResourceCacheGenerator 没有加载到相关资源。之后的 加载器(DataCacheGenerator,也可能是SourceGenerator,也可能是跳出循环,根据之前讲的相应设置有关) 会继续执行。
如果第一次加载,那么在 DataCacheGenerator 中,肯定是获取不到资源的,那么下一个会执行到 DataCacheGenerator 的 startNext() 方法
DataCacheGenerator#startNext
@Override public boolean startNext() { while (modelLoaders == null || !hasNextModelLoader()) { sourceIdIndex++; if (sourceIdIndex >= cacheKeys.size()) { return false; } //获取源资源的Key信息 Key sourceId = cacheKeys.get(sourceIdIndex);//cacheKeys=helper.getCacheKeys() //根据当前sourceId,获取对应的原始Key。 Key originalKey = new DataCacheKey(sourceId, helper.getSignature()); //根据原始的Key从磁盘缓存获取缓存文件,并且跳出循环 cacheFile = helper.getDiskCache().get(originalKey); if (cacheFile != null) { this.sourceKey = sourceId; modelLoaders = helper.getModelLoaders(cacheFile); modelLoaderIndex = 0; } } loadData = null; boolean started = false; while (!started && hasNextModelLoader()) { ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++); loadData = modelLoader.buildLoadData(cacheFile, helper.getWidth(), helper.getHeight(), helper.getOptions()); if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) { //有对应的LoadData started = true; //通过fetcher去加载对应的文件 loadData.fetcher.loadData(helper.getPriority(), this); } } return started; }
DataCacheGenerator 主要是获取原始的缓存文件。可以看到大体的流程是和 ResourceCacheGenerator 相似的。唯一的不同是,获取的Key不一样。在获取缓存文件的时候,使用的参数是 DataCacheKey ,也就是原始缓存文件的键值。
在首次进行加载的时候,这个肯定也是获取不到的,返回的是空,那么这时候,那么下一个会执行到 SourceGenerator 的 startNext() 方法。
SourceGenerator#startNext
public boolean startNext() { if (dataToCache != null) { //当第一次资源加载完成以后,会进行一次线程切换,而再次调用本方法,这时候dataToCache不为空,然后进行data的保存,此地是磁盘缓存源文件 // 并且生成了DataCacheGenerator类 Object data = dataToCache; dataToCache = null; cacheData(data); } if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) { //在有DataCacheGenerator类的情况下,会调用startNext方法,执行从源文件的加载文件 return true; } sourceCacheGenerator = null; loadData = null; boolean started = false; while (!started && hasNextModelLoader()) { //循环获取当前model相关的所有的modelLoaders,获取loadData数据 loadData = helper.getLoadData().get(loadDataListIndex++); //这里需要注意,假如缓存策略认为可以缓存data,那么就不需要管后面的loadPath,直接先把data获取。 //因为缓存之后将会移交给DataCacheGenerator处理,所以可以跳过后面的hasLoadPath判断。 //hasLoadPath是根据Registry中已经注册的解码器,转换器判断是否可以完成dataclass->resourceclass->transcodeclass的变换。 if (loadData != null && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource()) || helper.hasLoadPath(loadData.fetcher.getDataClass()))) { started = true; startNextLoad(loadData); } } return started; } private void startNextLoad(final LoadData<?> toStart) { loadData.fetcher.loadData(//进行资源的加载 helper.getPriority(), new DataCallback<Object>() { @Override public void onDataReady(@Nullable Object data) { if (isCurrentRequest(toStart)) { onDataReadyInternal(toStart, data); } } @Override public void onLoadFailed(@NonNull Exception e) { if (isCurrentRequest(toStart)) { onLoadFailedInternal(toStart, e); } } }); }
当进行资源加载完成以后,会通过回调 onDataReady 接口。我们看一下 onDataReadyInternal 的执行。
@Synthetic void onDataReadyInternal(LoadData<?> loadData, Object data) { DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy(); if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) { //如果DataFetcher对应的DataSource可以进行缓存 dataToCache = data; //这里的cb,指的是DecodeJob类->callback.reschedule(this),callback指的是EngineJob类 //->getActiveSourceExecutor().execute(job); //即通过线程池,重新执行了EngineJob,然后会执行到本类的startNext方法,因为dataToCache不为空,会执行里面的代码块 cb.reschedule(); } else { //如果不能进行缓存,则直接调用onDataFetcherReady方法 cb.onDataFetcherReady( loadData.sourceKey, data, loadData.fetcher, loadData.fetcher.getDataSource(), originalKey); } }
我们先分析第一种情况。
我们注释写的很详细了,也知道最后会重新调用本类的 startNext 方法,那么我们看看这个方法开始的部分。
if (dataToCache != null) { //当第一次资源加载完成以后,会进行一次线程切换,而再次调用本方法,这时候dataToCache不为空,然后进行data的保存,此地是磁盘缓存源文件 // 并且生成了DataCacheGenerator类 Object data = dataToCache; dataToCache = null; cacheData(data); } if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) { //在有DataCacheGenerator类的情况下,会调用startNext方法,执行从源文件的加载文件 return true; } private void cacheData(Object dataToCache) { long startTime = LogTime.getLogTime(); try { //获取到编码器,通过遍历注册表中编码器列表,获取到对应的cache类的编码器 Encoder<Object> encoder = helper.getSourceEncoder(dataToCache); //生成 DataCacheWriter<Object> writer = new DataCacheWriter<>(encoder, dataToCache, helper.getOptions()); //生成原始缓存文件的key,用于进行DataCacheGenerator中进行编码查找 originalKey = new DataCacheKey(loadData.sourceKey, helper.getSignature()); //通过DiskCache进行数据的缓存 helper.getDiskCache().put(originalKey, writer); } finally { loadData.fetcher.cleanup(); } sourceCacheGenerator = new DataCacheGenerator(Collections.singletonList(loadData.sourceKey), helper, this); }
也就是先在磁盘上保存原文件,然后通过DataCacheGenerator类再去进行加载。
现在我们看第二种情况:
public void onDataFetcherReady( Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) { ... if (Thread.currentThread() != currentThread) { //设置执行原因为DECODE_DATA,再重新调用unwrapper时,就可以直接执行解码阶段了。也就是下面else中的decodeFromRetrievedData方法 runReason = RunReason.DECODE_DATA; callback.reschedule(this); } else { GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData"); try { decodeFromRetrievedData(); } finally { GlideTrace.endSection(); } } }
这时候会根据线程进行一次重新调用,或者直接调用 decodeFromRetrievedData() 方法。
//解码检索到的的数据 private void decodeFromRetrievedData() { if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey( "Retrieved data", startFetchTime, "data: " + currentData + ", cache key: " + currentSourceKey + ", fetcher: " + currentFetcher); } Resource<R> resource = null; try { //进行资源的解码操作 resource = decodeFromData(currentFetcher, currentData, currentDataSource); } catch (GlideException e) { e.setLoggingDetails(currentAttemptingKey, currentDataSource); throwables.add(e); } if (resource != null) { //通过接口回调资源加载成功接口,然后进行层层回调由DecodeJon->EngineJob->Target中,最后由Target操作ImageView,将资源渲染到View上 notifyEncodeAndRelease(resource, currentDataSource); } else { runGenerators(); } }
大体的流程基本完成了。后续再对细节一点点进行增加。
补充几个文件:

ModelLoader(资源加载类):包含两个方法
buildLoadData():创建LoadData类
handles(Model):该类能否能够加载给定的模型
LoadData类:包含了3个属性
sourceKey:资源key
alternateKeys:临时key的列表
fetcher:持有的一个DataFetcher接口实例,定义了真正获取数据的loadData方法
DataFetcher接口:真正的资源获取
loadData():获取能够被解码的数据
cleanup():清空或者回收资源
getDataClass():当前实现类能获取的资源的类
getDataSource():此fetcher将从哪种数据源返回数据,枚举类型。
来源:https://www.cnblogs.com/kailaisii/p/12322971.html