https://www.cnblogs.com/billshen/p/13306285.html
https://blog.csdn.net/songzi1228/article/details/84426165
一、基本使用流程GlIDe最基本的使用流程就是下面这行代码,其它所有扩展的额外功能都是以其建造者链式调用的基础上增加的。
GlIDeApp.with(context).load(url).into(iv);复制代码
GlIDe全部的方法:
GlIDe.with(getApplicationContext()) // 指定Context .load(url)// 指定图片的URL .placeholder(R.mipmap.ic_launcher)// 指定图片未成功加载前显示的图片 .error(R.mipmap.ic_launcher)// 指定图片加载失败显示的图片 .overrIDe(300, 300)//指定图片的尺寸 .fitCenter()//指定图片缩放类型为 .centerCrop()// 指定图片缩放类型为 .skipMemoryCache(true)// 跳过内存缓存,不包括磁盘缓存 .diskCacheStrategy(diskCacheStrategy.NONE)//跳过磁盘缓存 .diskCacheStrategy(diskCacheStrategy.soURCE)//仅仅只缓存原来的全分辨率的图像 .diskCacheStrategy(diskCacheStrategy.RESulT)//仅仅缓存最终的图像 .diskCacheStrategy(diskCacheStrategy.ALL)//缓存所有版本的图像 .priority(Priority.HIGH)//指定优先级.GlIDe将会用他们作为一个准则,//并尽可能的处理这些请求, // 但是它不能保证所有的图片都会按照所要求的顺序加载。优先级排序: //IMMEDIATE > HIGH > norMAL > LOW .into(imageVIEw);//指定显示图片的ImagevIEw
其中的GlIDeApp是注解处理器自动生成的,要使用GlIDeApp,必须先配置应用的AppGlIDeModule模块,里面可以为空配置,也可以根据实际情况添加指定配置。
@GlIDeModulepublic class MyAppGlIDeModule extends AppGlIDeModule { @OverrIDe public voID applyOptions(Context context, GlIDeBuilder builder) { // 实际使用中根据情况可以添加如下配置 <!--builder.setDefaultRequestoptions(new Requestoptions().format(DecodeFormat.PREFER_RGB_565));--> <!--int memoryCacheSizeBytes = 1024 * 1024 * 20;--> <!--builder.setMemoryCache(new LruResourceCache(memoryCacheSizeBytes));--> <!--int bitmapPoolSizeBytes = 1024 * 1024 * 30;--> <!--builder.setBitmapPool(new LruBitmapPool(bitmapPoolSizeBytes));--> <!--int diskCacheSizeBytes = 1024 * 1024 * 100;--> <!--builder.setdiskCache(new InternalCachediskCacheFactory(context, diskCacheSizeBytes));--> }}复制代码
接下来,本文将针对GlIDe的最新源码版本V4.8.0对GlIDe加载网络图片的流程进行详细地分析与讲解,力争做到让读者朋友们知其然也知其所以然。
二、GlIDeApp.with(context)源码详解首先,用艽野尘梦绘制的这份GlIDe框架图让我们对GlIDe的总体框架有一个初步的了解。
从GlIDeApp.with这行代码开始,内部主线执行流程如下。
1、GlIDeApp#with
return (GlIDeRequests) GlIDe.with(context);复制代码
2、GlIDe#with
return getRetrIEver(context).get(context);return GlIDe.get(context).getRequestManagerRetrIEver();// 外部使用了双重检锁的同步方式确保同一时刻只执一次GlIDe的初始化checkAndInitializeGlIDe(context);initializeGlIDe(context);// 最终执行到GlIDe的另一个重载方法initializeGlIDe(context, new GlIDeBuilder());@SuppressWarnings("deprecation") private static voID initializeGlIDe(@NonNull Context context, @NonNull GlIDeBuilder builder) { Context applicationContext = context.getApplicationContext(); // 1、获取前面应用中带注解的GlIDeModule GeneratedAppGlIDeModule annotationGeneratedModule = getAnnotationGeneratedGlIDeModules(); // 2、如果GlIDeModule为空或者可配置manifest里面的标志为true,则获取manifest里面 // 配置的GlIDeModule模块(manifestModules)。 List<com.bumptech.glIDe.module.GlIDeModule> manifestModules = Collections.emptyList(); if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled( )) { manifestModules = new ManifestParser(applicationContext).parse(); } ... RequestManagerRetrIEver.RequestManagerFactory factory = annotationGeneratedModule != null ? annotationGeneratedModule.getRequestManag erFactory() : null; builder.setRequestManagerFactory(factory); for (com.bumptech.glIDe.module.GlIDeModule module : manifestModules) { module.applyOptions(applicationContext, builder); } if (annotationGeneratedModule != null) { annotationGeneratedModule.applyOptions(applicatio nContext, builder); } // 3、初始化各种配置信息 GlIDe glIDe = builder.build(applicationContext); // 4、把manifestModules以及annotationGeneratedModule里面的配置信息放到builder // 里面(applyOptions)替换glIDe默认组件(registerComponents) for (com.bumptech.glIDe.module.GlIDeModule module : manifestModules) { module.registerComponents(applicationContext, glIDe, glIDe.registry); } if (annotationGeneratedModule != null) { annotationGeneratedModule.registerComponents(appl icationContext, glIDe, glIDe.registry); } applicationContext.registerComponentCallbacks(glIDe ); GlIDe.glIDe = glIDe;}复制代码
3、GlIDeBuilder#build
@NonNull GlIDe build(@NonNull Context context) { // 创建请求图片线程池sourceExecutor if (sourceExecutor == null) { sourceExecutor = GlIDeExecutor.newSourceExecutor(); } // 创建硬盘缓存线程池diskCacheExecutor if (diskCacheExecutor == null) { diskCacheExecutor = GlIDeExecutor.newdiskCacheExecutor(); } // 创建动画线程池animationExecutor if (animationExecutor == null) { animationExecutor = GlIDeExecutor.newAnimationExecutor(); } if (memorySizeCalculator == null) { memorySizeCalculator = new MemorySizeCalculator.Builder(context).build(); } if (connectivityMonitorFactory == null) { connectivityMonitorFactory = new DefaultConnectivityMonitorFactory(); } if (bitmapPool == null) { // 依据设备的屏幕密度和尺寸设置各种pool的size int size = memorySizeCalculator.getBitmapPoolSize(); if (size > 0) { // 创建图片线程池LruBitmapPool,缓存所有被释放的bitmap // 缓存策略在API大于19时,为SizeConfigStrategy,小于为AttributeStrategy。 // 其中SizeConfigStrategy是以bitmap的size和config为key,value为bitmap的HashMap bitmapPool = new LruBitmapPool(size); } else { bitmapPool = new BitmapPoolAdapter(); } } // 创建对象数组缓存池LruArrayPool,默认4M if (arrayPool == null) { arrayPool = new LruArrayPool(memorySizeCalculator.getarraypoolsiz eInBytes()); } // 创建LruResourceCache,内存缓存 if (memoryCache == null) { memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCa cheSize()); } if (diskCacheFactory == null) { diskCacheFactory = new InternalCachediskCacheFactory(context); } // 创建任务和资源管理引擎(线程池,内存缓存和硬盘缓存对象) if (engine == null) { engine = new Engine( memoryCache, diskCacheFactory, diskCacheExecutor, sourceExecutor, GlIDeExecutor.newUnlimitedSourceExecutor( ), GlIDeExecutor.newAnimationExecutor(), isActiveResourceRetentionAllowed); } RequestManagerRetrIEver requestManagerRetrIEver = new RequestManagerRetrIEver(requestManagerFactory); return new GlIDe( context, engine, memoryCache, bitmapPool, arrayPool, requestManagerRetrIEver, connectivityMonitorFactory, logLevel, defaultRequestoptions.lock(), defaultTransitionOptions);}复制代码
4、GlIDe#GlIDe构造方法
GlIDe(...) { ... // 注册管理任务执行对象的类(Registry) // Registry是一个工厂,而其中所有注册的对象都是一个工厂员工,当任务分发时, // 根据当前任务的性质,分发给相应员工进行处理 registry = new Registry(); ... // 这里大概有60余次的append或register员工组件(解析器、编解码器、工厂类、转码类等等组件) registry .append(ByteBuffer.class, new ByteBufferEncoder()) .append(inputStream.class, new StreamEncoder(arrayPool)) // 根据给定子类产出对应类型的target(BitmAPImageVIEwTarget / DrawableImageVIEwTarget) ImageVIEwTargetFactory imageVIEwTargetFactory = new ImageVIEwTargetFactory(); glIDeContext = new GlIDeContext( context, arrayPool, registry, imageVIEwTargetFactory, defaultRequestoptions, defaultTransitionOptions, engine, logLevel);} 复制代码
5、RequestManagerRetrIEver#get
@NonNullpublic 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)) { // 如果当前线程是主线程且context不是Application走相应的get重载方法 if (context instanceof FragmentActivity) { return get((FragmentActivity) context); } else if (context instanceof Activity) { return get((Activity) context); } else if (context instanceof Contextwrapper) { return get(((Contextwrapper) context).getBaseContext()); } } // 否则直接将请求与Applicationlifecycle关联 return getApplicationManager(context);}复制代码
这里总结一下,对于当前传入的context是application或当前线程是子线程时,请求的生命周期和Applicationlifecycle关联,否则,context是FragmentActivity或Fragment时,在当前组件添加一个SupportFragment(SupportRequestManagerFragment),context是Activity时,在当前组件添加一个Fragment(RequestManagerFragment)。
6、GlIDeApp#with小结
1、初始化各式各样的配置信息(包括缓存,请求线程池,大小,图片格式等等)以及glIDe对象。
2、将glIDe请求和application/SupportFragment/Fragment的生命周期绑定在一块。
这里我们再回顾一下with方法的执行流程。
三、load(url)源码详解1、GlIDeRequest(RequestManager)#load
return (GlIDeRequest<Drawable>) super.load(string);return asDrawable().load(string);// 1、asDrawable部分return (GlIDeRequest<Drawable>) super.asDrawable();return as(Drawable.class);// 最终返回了一个GlIDeRequest(RequestManager的子类)return new GlIDeRequest<>(glIDe, this, resourceClass, context);// 2、load部分return (GlIDeRequest<TranscodeType>) super.load(string);return loadGeneric(string);@NonNullprivate RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) { // model则为设置的url this.model = model; // 记录url已设置 isModelSet = true; return this;}复制代码
可以看到,load这部分的源码很简单,就是给GlIDeRequest(RequestManager)设置了要请求的mode(url),并记录了url已设置的状态。
这里,我们再看看load方法的执行流程。
四、into(iv)源码详解前方预警,真正复杂的地方开始了。
1、RequestBuilder.into
@NonNullpublic VIEwTarget<ImageVIEw, TranscodeType> into(@NonNull ImageVIEw vIEw) { Util.assertMainThread(); Preconditions.checkNotNull(vIEw); Requestoptions requestoptions = this.requestoptions; if (!requestoptions.istransformationSet() && requestoptions.istransformationAllowed() && vIEw.getScaleType() != null) { // Clone in this method so that if we use this RequestBuilder to load into a VIEw and then // into a different target, we don't retain the transformation applIEd based on the prevIoUs // VIEw's scale type. switch (vIEw.getScaleType()) { // 这个Requestoptions里保存了要设置的scaleType,GlIDe自身封装了CenterCrop、CenterInsIDe、 // FitCenter、CenterInsIDe四种规格。 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. } } // 注意,这个transcodeClass是指的drawable或bitmap return into( glIDeContext.buildImageVIEwTarget(vIEw, transcodeClass), /*targetListener=*/ null, requestoptions);}复制代码
2、GlIDeContext#buildImageVIEwTarget
return imageVIEwTargetFactory.buildTarget(imageVIEw, transcodeClass); 复制代码
3、ImageVIEwTargetFactory#buildTarget
@NonNull@SuppressWarnings("unchecked")public <Z> VIEwTarget<ImageVIEw, Z> buildTarget(@NonNull ImageVIEw vIEw, @NonNull Class<Z> clazz) { // 返回展示Bimtap/Drawable资源的目标对象 if (Bitmap.class.equals(clazz)) { return (VIEwTarget<ImageVIEw, Z>) new BitmAPImageVIEwTarget(vIEw); } else if (Drawable.class.isAssignableFrom(clazz)) { return (VIEwTarget<ImageVIEw, Z>) new DrawableImageVIEwTarget(vIEw); } else { throw new IllegalArgumentException( "Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)"); }}复制代码
可以看到,GlIDe内部只维护了两种target,一种是BitmAPImageVIEwTarget,另一种则是DrawableImageVIEwTarget,接下来继续深入。
4、RequestBuilder#into
private <Y extends Target<TranscodeType>> Y into( @NonNull Y target, @Nullable RequestListener<TranscodeType> targetListener, @NonNull Requestoptions options) { Util.assertMainThread(); Preconditions.checkNotNull(target); if (!isModelSet) { throw new IllegalArgumentException("You must call #load() before calling #into()"); } options = options.autoClone(); // 分析1.建立请求 Request request = buildrequest(target, targetListener, options); Request prevIoUs = target.getRequest(); if (request.isEquivalentTo(prevIoUs) && !isSkipMemoryCacheWithCompletePrevIoUsReques t(options, prevIoUs)) { request.recycle(); // If the request is completed, beginning again will ensure the result is re-delivered, // triggering RequestListeners and Targets. If the request is Failed, beginning again will // restart the request, giving it another chance to complete. If the request is already // running, we can let it continue running without interruption. if (!Preconditions.checkNotNull(prevIoUs).isRunni ng()) { // Use the prevIoUs request rather than the new one to allow for optimizations like skipPing // setting placeholders, tracking and un-tracking Targets, and obtaining VIEw dimensions // that are done in the indivIDual Request. prevIoUs.begin(); } return target; } requestManager.clear(target); target.setRequest(request); // 分析2.真正追踪请求的地方 requestManager.track(target, request); return target;}// 分析1private Request buildrequest( Target<TranscodeType> target, @Nullable RequestListener<TranscodeType> targetListener, Requestoptions requestoptions) { return buildrequestRecursive( target, targetListener, /*parentCoordinator=*/ null, TransitionOptions, requestoptions.getPriority(), requestoptions.getoverrIDeWIDth(), requestoptions.getoverrIDeHeight(), requestoptions);}// 分析1private Request buildrequestRecursive( Target<TranscodeType> target, @Nullable RequestListener<TranscodeType> targetListener, @Nullable RequestCoordinator parentCoordinator, TransitionOptions<?, ? super TranscodeType> TransitionOptions, Priority priority, int overrIDeWIDth, int overrIDeHeight, Requestoptions requestoptions) { // Build the ErrorRequestCoordinator first if necessary so we can update parentCoordinator. ErrorRequestCoordinator errorRequestCoordinator = null; if (errorBuilder != null) { // 创建errorRequestCoordinator(异常处理对象) errorRequestCoordinator = new ErrorRequestCoordinator(parentCoordinator); parentCoordinator = errorRequestCoordinator; } // 递归建立缩略图请求 Request mainRequest = buildthumbnailRequestRecursive( target, targetListener, parentCoordinator, TransitionOptions, priority, overrIDeWIDth, overrIDeHeight, requestoptions); if (errorRequestCoordinator == null) { return mainRequest; } ... Request errorRequest = errorBuilder.buildrequestRecursive( target, targetListener, errorRequestCoordinator, errorBuilder.TransitionOptions, errorBuilder.requestoptions.getPriority(), errorOverrIDeWIDth, errorOverrIDeHeight, errorBuilder.requestoptions); errorRequestCoordinator.setRequests(mainRequest, errorRequest); return errorRequestCoordinator;}// 分析1private Request buildthumbnailRequestRecursive( Target<TranscodeType> target, RequestListener<TranscodeType> targetListener, @Nullable RequestCoordinator parentCoordinator, TransitionOptions<?, ? super TranscodeType> TransitionOptions, Priority priority, int overrIDeWIDth, int overrIDeHeight, Requestoptions requestoptions) { if (thumbnailBuilder != null) { // Recursive case: contains a potentially recursive thumbnail request builder. ... thumbnailRequestCoordinator coordinator = new thumbnailRequestCoordinator(parentCoordinator); // 获取一个正常请求对象 Request fullRequest = obtainRequest( target, targetListener, requestoptions, coordinator, TransitionOptions, priority, overrIDeWIDth, overrIDeHeight); isthumbnailBuilt = true; // Recursively generate thumbnail requests. // 使用递归的方式建立一个缩略图请求对象 Request thumbRequest = thumbnailBuilder.buildrequestRecursive( target, targetListener, coordinator, thumbTransitionOptions, thumbPriority, thumbOverrIDeWIDth, thumbOverrIDeHeight, thumbnailBuilder.requestoptions); isthumbnailBuilt = false; // coordinator(thumbnailRequestCoordinator)是作为两者的协调者, // 能够同时加载缩略图和正常的图的请求 coordinator.setRequests(fullRequest, thumbRequest); return coordinator; } else if (thumbSizeMultiplIEr != null) { // Base case: thumbnail multiplIEr generates a thumbnail request, but cannot recurse. // 当设置了缩略的比例thumbSizeMultiplIEr(0 ~ 1)时, // 不需要递归建立缩略图请求 thumbnailRequestCoordinator coordinator = new thumbnailRequestCoordinator(parentCoordinator); Request fullRequest = obtainRequest( target, targetListener, requestoptions, coordinator, TransitionOptions, priority, overrIDeWIDth, overrIDeHeight); Requestoptions thumbnailOptions = requestoptions.clone() .sizeMultiplIEr(thumbSizeMultiplIEr); Request thumbnailRequest = obtainRequest( target, targetListener, thumbnailOptions, coordinator, TransitionOptions, getthumbnailPriority(priority), overrIDeWIDth, overrIDeHeight); coordinator.setRequests(fullRequest, thumbnailRequest); return coordinator; } else { // Base case: no thumbnail. // 没有缩略图请求时,直接获取一个正常图请求 return obtainRequest( target, targetListener, requestoptions, parentCoordinator, TransitionOptions, priority, overrIDeWIDth, overrIDeHeight); }}private Request obtainRequest( Target<TranscodeType> target, RequestListener<TranscodeType> targetListener, Requestoptions requestoptions, RequestCoordinator requestCoordinator, TransitionOptions<?, ? super TranscodeType> TransitionOptions, Priority priority, int overrIDeWIDth, int overrIDeHeight) { // 最终实际返回的是一个SingleRequest对象(将制定的资源加载进对应的Target return SingleRequest.obtain( context, glIDeContext, model, transcodeClass, requestoptions, overrIDeWIDth, overrIDeHeight, priority, target, targetListener, requestListeners, requestCoordinator, glIDeContext.getEngine(), TransitionOptions.getTransitionFactory());}复制代码
从上源码分析可知,我们在分析1处的buildrequest()方法里建立了请求,且最多可同时进行缩略图和正常图的请求,最后,调用了requestManager.track(target, request)方法,接着看看track里面做了什么。
5、RequestManager#track
// 分析2voID track(@NonNull Target<?> target, @NonNull Request request) { // 加入一个target目标集合(Set) targetTracker.track(target); requestTracker.runRequest(request);}复制代码
6、RequestTracker#runRequest
/*** Starts tracking the given request.*/// 分析2public 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"); } // 否则清空请求,加入延迟请求队列(为了对这些请求维持一个强引用,使用了ArrayList实现) pendingRequests.add(request); }}复制代码
7、SingleRequest#begin
// 分析2@OverrIDepublic voID begin() { ... if (model == null) { ... // model(url)为空,回调加载失败 onl oadFailed(new GlIDeException("Received null model"), logLevel); return; } 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)) { // 当使用overrIDe() API为图片指定了一个固定的宽高时直接执行onSizeReady, // 最终的核心处理位于onSizeReady onSizeReady(overrIDeWIDth, overrIDeHeight); } else { // 根据imageVIEw的宽高算出图片的宽高,最终也会走到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)); }}复制代码
从requestManager.track(target, request)开始,最终会执行到SingleRequest#begin()方法的onSizeReady,可以猜到(因为后面只做了预加载缩略图的处理),真正的请求就是从这里开始的,咱们进去一探究竟~
8、SingleRequest#onSizeReady
// 分析2@OverrIDepublic voID onSizeReady(int wIDth, int height) { stateVerifIEr.throwIfRecycled(); ... status = Status.RUNNING; float sizeMultiplIEr = requestoptions.getSizeMultiplIEr(); this.wIDth = maybeApplySizeMultiplIEr(wIDth, sizeMultiplIEr); this.height = maybeApplySizeMultiplIEr(height, sizeMultiplIEr); ... // 根据给定的配置进行加载,engine是一个负责加载、管理活跃和缓存资源的引擎类 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.getUseUnlimitedSourceGeneratorsP ool(), requestoptions.getUseAnimationPool(), requestoptions.getonlyRetrIEveFromCache(), this); ...}复制代码
终于看到Engine类了,感觉距离成功不远了,继续~
9、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) { ... // 先从弱引用中查找,如果有的话回调onResourceReady并直接返回 EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable); if (active != null) { cb.onResourceReady(active, DataSource.MEMORY_CACHE); if (VERBOSE_IS_LOGGABLE) { logWithTimeAndKey("Loaded resource from active resources", startTime, key); } return null; } // 没有再从内存中查找,有的话会取出并放到ActiveResources(内部维护的弱引用缓存map)里面 EngineResource<?> cached = loadFromCache(key, isMemoryCacheable); if (cached != null) { cb.onResourceReady(cached, DataSource.MEMORY_CACHE); if (VERBOSE_IS_LOGGABLE) { logWithTimeAndKey("Loaded resource from cache", startTime, key); } return null; } EngineJob<?> current = jobs.get(key, onlyRetrIEveFromCache); if (current != null) { current.addCallback(cb); if (VERBOSE_IS_LOGGABLE) { logWithTimeAndKey("Added to existing load", startTime, key); } return new LoadStatus(cb, current); } // 如果内存中没有,则创建engineJob(decodejob的回调类,管理下载过程以及状态) EngineJob<R> engineJob = engineJobFactory.build( key, isMemoryCacheable, useUnlimitedSourceExecutorPool, useAnimationPool, onlyRetrIEveFromCache); // 创建解析工作对象 DecodeJob<R> decodeJob = decodeJobFactory.build( glIDeContext, model, key, signature, wIDth, height, resourceClass, transcodeClass, priority, diskCacheStrategy, transformations, istransformationrequired, isScaleOnlyOrNotransform, onlyRetrIEveFromCache, options, engineJob); // 放在Jobs内部维护的HashMap中 jobs.put(key, engineJob); // 关注点8 后面分析会用到 // 注册ResourceCallback接口 engineJob.addCallback(cb); // 内部开启线程去请求 engineJob.start(decodeJob); if (VERBOSE_IS_LOGGABLE) { logWithTimeAndKey("Started new load", startTime, key); } return new LoadStatus(cb, engineJob);}public voID start(DecodeJob<R> decodeJob) { this.decodeJob = decodeJob; // willDecodeFromCache方法内部根据不同的阶段stage,如果是RESOURCE_CACHE/DATA_CACHE则返回true,使用diskCacheExecutor,否则调用getActiveSourceExecutor,内部会根据相应的条件返回sourceUnlimitedExecutor/animationExecutor/sourceExecutor GlIDeExecutor executor = decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor(); executor.execute(decodeJob);}复制代码
可以看到,最终Engine(引擎)类内部会执行到自身的start方法,它会根据不同的配置采用不同的线程池使用diskCacheExecutor/sourceUnlimitedExecutor/animationExecutor/sourceExecutor来执行最终的解码任务decodeJob。
10、DecodeJob#run
runWrapped();private voID runWrapped() { switch (runReason) { case INITIAliZE: stage = getNextStage(Stage.INITIAliZE); // 关注点1 currentGenerator = getNextGenerator(); // 关注点2 内部会调用相应Generator的startNext() runGenerators(); break; case SWITCH_TO_SOURCE_SERVICE: runGenerators(); break; case DECODE_DATA: // 关注点3 将获取的数据解码成对应的资源 decodeFromretrIEvedData(); break; default: throw new IllegalStateException("Unrecognized run reason: " + runReason); }}// 关注点1,完整情况下,会异步依次生成这里的ResourceCacheGenerator、DataCacheGenerator和SourceGenerator对象,并在之后执行其中的startNext()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); }}复制代码
11、SourceGenerator#startNext
// 关注点2@OverrIDepublic boolean startNext() { // dataToCache数据不为空的话缓存到硬盘(第一执行该方法是不会调用的) if (dataToCache != null) { Object data = dataToCache; dataToCache = null; cacheData(data); } if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) { return true; } sourceCacheGenerator = null; loadData = null; boolean started = false; while (!started && hasNextModelLoader()) { // 关注点4 getLoadData()方法内部会在modelLoaders里面找到ModelLoder对象 // (每个Generator对应一个ModelLoader), // 并使用modelLoader.buildLoadData方法返回一个loadData列表 loadData = helper.getLoadData().get(loadDataListIndex++); if (loadData != null && (helper.getdiskCacheStrategy().isDataCache able(loadData.fetcher.getDataSource()) || helper.hasLoa@R_419_5819@(loadData.fetcher.getDat aClass()))) { started = true; // 关注点6 通过loadData对象的fetcher对象(有关注点3的分析可知其实现类为httpUrlFetcher)的 // loadData方法来获取图片数据 loadData.fetcher.loadData(helper.getPriority(), this); } } return started;}复制代码
12、DecodeHelper#getLoadData
List<LoadData<?>> getLoadData() { if (!isLoadDataSet) { isLoadDataSet = true; loadData.clear(); List<ModelLoader<Object, ?>> modelLoaders = glIDeContext.getRegistry().getModelLoaders(model) ; //noinspection ForLoopReplaceableByForEach to improve perf for (int i = 0, size = modelLoaders.size(); i < size; i++) { ModelLoader<Object, ?> modelLoader = modelLoaders.get(i); // 注意:这里最终是通过httpGlIDeUrlLoader的buildLoadData获取到实际的loadData对象 LoadData<?> current = modelLoader.buildLoadData(model, wIDth, height, options); if (current != null) { loadData.add(current); } } } return loadData;}复制代码
13、httpGlIDeUrlLoader#buildLoadData
@OverrIDepublic LoadData<inputStream> buildLoadData(@NonNull GlIDeUrl model, int wIDth, int height, @NonNull Options options) { // GlIDeUrls memoize parsed URLs so caching them saves a few object instantiations and time // spent parsing urls. GlIDeUrl url = model; if (modelCache != null) { url = modelCache.get(model, 0, 0); if (url == null) { // 关注点5 modelCache.put(model, 0, 0, model); url = model; } } int timeout = options.get(TIMEOUT); // 注意,这里创建了一个DataFetcher的实现类httpUrlFetcher return new LoadData<>(url, new httpUrlFetcher(url, timeout));}// 关注点5public voID put(A model, int wIDth, int height, B value) { ModelKey<A> key = ModelKey.get(model, wIDth, height); // 最终是通过LruCache来缓存对应的值,key是一个ModelKey对象(由model、wIDth、height三个属性组成) cache.put(key, value);}复制代码
从这里的分析,我们明白了httpUrlFetcher实际上就是最终的请求执行者,而且,我们知道了GlIDe会使用LruCache来对解析后的url来进行缓存,以便后续可以省去解析url的时间。
14、httpUrlFetcher#loadData
@OverrIDepublic voID loadData(@NonNull Priority priority, @NonNull DataCallback<? super inputStream> callback) { long startTime = LogTime.getLogTime(); try { // 关注点6 // loadDataWithRedirects内部是通过httpURLConnection网络请求数据 inputStream result = loadDataWithRedirects(glIDeUrl.toURL(), 0, null, glIDeUrl.getheaders()); // 请求成功回调onDataReady() callback.onDataReady(result); } catch (IOException e) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "Failed to load data for url", e); } callback.onLoadFailed(e); } finally { if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "Finished http url fetcher fetch in " + LogTime.getElapsedMillis(startTime)); } }}private inputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl, Map<String, String> headers) throws IOException { ... 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(); // 只要是2xx形式的状态码则判断为成功 if (ishttpOk(statusCode)) { // 从urlConnection中获取资源流 return getStreamForSuccessfulRequest(urlConnection); } else if (ishttpRedirect(statusCode)) { ... // 重定向请求 return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers); } else if (statusCode == INVALID_STATUS_CODE) { throw new httpException(statusCode); } else { throw new httpException(urlConnection.getResponseMessage(), statusCode); }}private inputStream getStreamForSuccessfulRequest(httpURLConnection urlConnection) throws IOException { if (TextUtils.isEmpty(urlConnection.getContentEnCoding())) { int contentLength = urlConnection.getContentLength(); stream = ContentLengthinputStream.obtain(urlConnection.getinputStr eam(), contentLength); } else { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "Got non empty content enCoding: " + urlConnection.getContentEnCoding()); } stream = urlConnection.getinputStream(); } return stream;}复制代码
在httpUrlFetcher#loadData方法的loadDataWithRedirects里面,GlIDe通过原生的httpURLConnection进行请求后,并调用getStreamForSuccessfulRequest()方法获取到了最终的图片流。
15、DecodeJob#run
在我们通过HtttpUrlFetcher的loadData()方法请求得到对应的流之后,我们还必须对流进行处理得到最终我们想要的资源。这里我们回到第10步DecodeJob#run方法的关注点3处,这行代码将会对流进行解码。
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) { // 关注点8 // 编码和发布最终得到的Resource<Bitmap>对象 notifyEncodeAndRelease(resource, currentDataSource); } else { runGenerators(); }} private <Data> Resource<R> decodeFromData(DataFetcher<?> fetcher, Data data, DataSource dataSource) throws GlIDeException { try { if (data == null) { return null; } long startTime = LogTime.getLogTime(); // 核心代码 // 进一步包装了解码方法 Resource<R> result = decodeFromFetcher(data, dataSource); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Decoded result " + result, startTime); } return result; } finally { fetcher.cleanup(); }}@SuppressWarnings("unchecked")private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource) throws GlIDeException { Loa@R_419_5819@<Data, ?, R> path = decodeHelper.getLoa@R_419_5819@((Class<Data>) data.getClass()); // 核心代码 // 将解码任务分发给Loa@R_419_5819@ return runLoa@R_419_5819@(data, dataSource, path);}private <Data, ResourceType> Resource<R> runLoa@R_419_5819@(Data data, DataSource dataSource, Loa@R_419_5819@<Data, ResourceType, R> path) throws GlIDeException { Options options = getoptionsWithHarDWareConfig(dataSource); // 将数据进一步包装 DataRewinder<Data> rewinder = glIDeContext.getRegistry().getRewinder(data); try { // ResourceType in DecodeCallback below is required for compilation to work with gradle. // 核心代码 // 将解码任务分发给Loa@R_419_5819@ return path.load( rewinder, options, wIDth, height, new DecodeCallback<ResourceType>(dataSource)); } finally { rewinder.cleanup(); }}复制代码
16、Loa@R_419_5819@#load
public Resource<Transcode> load(DataRewinder<Data> rewinder, @NonNull Options options, int wIDth, int height, DecodePath.DecodeCallback<ResourceType> decodeCallback) throws GlIDeException {List<Throwable> throwables = Preconditions.checkNotNull(ListPool.acquire());try { // 核心代码 return loaDWithExceptionList(rewinder, options, wIDth, height, decodeCallback, throwables);} finally { ListPool.release(throwables);}复制代码
}
private Resource<Transcode> loaDWithExceptionList(DataRewinder<Data> rewinder, @NonNull Options options, int wIDth, int height, DecodePath.DecodeCallback<ResourceType> decodeCallback, List<Throwable> exceptions) throws GlIDeException { Resource<Transcode> result = null; //noinspection ForLoopReplaceableByForEach to improve perf for (int i = 0, size = decodePaths.size(); i < size; i++) { DecodePath<Data, ResourceType, Transcode> 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;}复制代码
17、DecodePath#decode
public Resource<Transcode> decode(DataRewinder<DataType> rewinder, int wIDth, int height, @NonNull Options options, DecodeCallback<ResourceType> callback) throws GlIDeException { // 核心代码 // 继续调用DecodePath的decodeResource方法去解析出数据 Resource<ResourceType> decoded = decodeResource(rewinder, wIDth, height, options); Resource<ResourceType> transformed = callback.onResourceDecoded(decoded); return transcoder.transcode(transformed, options);}@NonNullprivate Resource<ResourceType> decodeResource(DataRewinder<DataType> rewinder, int wIDth, int height, @NonNull Options options) throws GlIDeException { List<Throwable> exceptions = Preconditions.checkNotNull(ListPool.acquire()); try { // 核心代码 return decodeResourceWithList(rewinder, wIDth, height, options, exceptions); } finally { ListPool.release(exceptions); }}@NonNullprivate Resource<ResourceType> decodeResourceWithList(DataRewinder<DataType> rewinder, int wIDth, int height, @NonNull Options options, List<Throwable> exceptions) throws GlIDeException { Resource<ResourceType> result = null; //noinspection ForLoopReplaceableByForEach to improve perf for (int i = 0, size = decoders.size(); i < size; i++) { ResourceDecoder<DataType, ResourceType> 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 | OutOfMemoryError e) { if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "Failed to decode data for " + decoder, e); } exceptions.add(e); } if (result != null) { break; } } if (result == null) { throw new GlIDeException(failureMessage, new ArrayList<>(exceptions)); } return result;}复制代码
可以看到,经过一连串的嵌套调用,最终执行到了decoder.decode()这行代码,decode是一个ResourceDecoder<DataType, ResourceType>接口(资源解码器),根据不同的DataType和ResourceType它会有不同的实现类,这里的实现类是ByteBufferBitmapDecoder,接下来让我们来看看这个解码器内部的解码流程。
18、ByteBufferBitmapDecoder#decode
/** * Decodes {@link androID.graphics.Bitmap Bitmaps} from {@link java.nio.ByteBuffer ByteBuffers}. */public class ByteBufferBitmapDecoder implements ResourceDecoder<ByteBuffer, Bitmap> { ... @OverrIDe public Resource<Bitmap> decode(@NonNull ByteBuffer source, int wIDth, int height, @NonNull Options options) throws IOException { inputStream is = ByteBufferUtil.toStream(source); // 核心代码 return downsampler.decode(is, wIDth, height, options); }}复制代码
可以看到,最终是使用了一个downsampler,它是一个压缩器,主要是对流进行解码,压缩,圆角等处理。
19、DownSampler#decode
public Resource<Bitmap> decode(inputStream is, int outWIDth, int outHeight, Options options) throws IOException { return decode(is, outWIDth, outHeight, options, EMPTY_CALLBACKS);} @SuppressWarnings({"resource", "deprecation"})public Resource<Bitmap> decode(inputStream is, int requesteDWIDth, int requestedHeight, Options options, DecodeCallbacks callbacks) throws IOException { Preconditions.checkArgument(is.markSupported(), "You must provIDe an inputStream that supports" + " mark()"); ... try { // 核心代码 Bitmap result = decodeFromWrappedStreams(is, bitmapFactoryOptions, downsampleStrategy, decodeFormat, isHarDWareConfigAllowed, requesteDWIDth, requestedHeight, fixBitmapToRequestedDimensions, callbacks); // 关注点7 // 解码得到Bitmap对象后,包装成BitmapResource对象返回, // 通过内部的get方法得到Resource<Bitmap>对象 return BitmapResource.obtain(result, bitmapPool); } finally { releaSEOptions(bitmapFactoryOptions); byteArrayPool.put(bytesForOptions); }}private Bitmap decodeFromWrappedStreams(inputStream is, BitmapFactory.Options options, DownsampleStrategy downsampleStrategy, DecodeFormat decodeFormat, boolean isHarDWareConfigAllowed, int requesteDWIDth, int requestedHeight, boolean fixBitmapToRequestedDimensions, DecodeCallbacks callbacks) throws IOException { // 省去计算压缩比例等一系列非核心逻辑 ... // 核心代码 Bitmap downsampled = decodeStream(is, options, callbacks, bitmapPool); callbacks.onDecodeComplete(bitmapPool, downsampled); ... // Bimtap旋转处理 ... return rotated;}private static Bitmap decodeStream(inputStream is, BitmapFactory.Options options, DecodeCallbacks callbacks, BitmapPool bitmapPool) throws IOException { ... transformationUtils.getBitmapDrawableLock().lock(); try { // 核心代码 result = BitmapFactory.decodeStream(is, null, options); } catch (IllegalArgumentException e) { ... } finally { transformationUtils.getBitmapDrawableLock().unlock(); } if (options.inJustDecodeBounds) { is.reset(); } return result;}复制代码
从以上源码流程我们知道,最后是在DownSampler的decodeStream()方法中使用了BitmapFactory.decodeStream()来得到Bitmap对象。然后,我们来分析下图片时如何显示的,我们回到步骤19的DownSampler#decode方法,看到关注点7,这里是将Bitmap包装成BitmapResource对象返回,通过内部的get方法可以得到Resource对象,再回到步骤15的DecodeJob#run方法,这是使用了notifyEncodeAndRelease()方法对Resource对象进行了发布。
20、DecodeJob#notifyEncodeAndRelease
private voID notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) { ... notifyComplete(result, dataSource); ... }private voID notifyComplete(Resource<R> resource, DataSource dataSource) { setNotifIEdOrThrow(); callback.onResourceReady(resource, dataSource);}复制代码
从以上EngineJob的源码可知,它实现了DecodeJob.CallBack这个接口。
class EngineJob<R> implements DecodeJob.Callback<R>, Poolable { ...}复制代码
21、EngineJob#onResourceReady
@OverrIDepublic voID onResourceReady(Resource<R> resource, DataSource dataSource) { this.resource = resource; this.dataSource = dataSource; MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();}private static class MainThreadCallback implements Handler.Callback{ ... @OverrIDe public boolean handleMessage(Message message) { EngineJob<?> job = (EngineJob<?>) message.obj; switch (message.what) { case MSG_COMPLETE: // 核心代码 job.handleResultOnMainThread(); break; ... } return true; }}复制代码
从以上源码可知,通过主线程Handler对象进行切换线程,然后在主线程调用了handleResultOnMainThread这个方法。
@SyntheticvoID handleResultOnMainThread() { ... //noinspection ForLoopReplaceableByForEach to improve perf for (int i = 0, size = cbs.size(); i < size; i++) { ResourceCallback cb = cbs.get(i); if (!isInIgnoredCallbacks(cb)) { engineResource.acquire(); cb.onResourceReady(engineResource, dataSource); } } ...}复制代码
这里又通过一个循环调用了所有ResourceCallback的方法,让我们回到步骤9处Engine#load方法的关注点8这行代码,这里对ResourceCallback进行了注册,在步骤8出SingleRequest#onSizeReady方法里的engine.load中,我们看到最后一个参数,传入的是this,可以明白,engineJob.addCallback(cb)这里的cb的实现类就是SingleRequest。接下来,让我们看看SingleRequest的onResourceReady方法。
22、SingleRequest#onResourceReady
/** * A callback method that should never be invoked directly. */@SuppressWarnings("unchecked")@OverrIDepublic voID onResourceReady(Resource<?> resource, DataSource dataSource) { ... // 从Resource<Bitmap>中得到Bitmap对象 Object received = resource.get(); ... onResourceReady((Resource<R>) resource, (R) received, dataSource);}private voID onResourceReady(Resource<R> resource, R resultDataSource dataSource) { ... try { ... if (!anyListenerHandledUpdatingTarget) { Transition<? super R> animation = animationFactory.build(dataSource, isFirstResource); // 核心代码 target.onResourceReady(result, animation); } } finally { isCallingCallbacks = false; } notifyLoadSuccess();}复制代码
在SingleRequest#onResourceReady方法中又调用了target.onResourceReady(result, animation)方法,这里的target其实就是我们在into方法中建立的那个BitmAPImageVIEwTarget,看到BitmAPImageVIEwTarget类,我们并没有发现onResourceReady方法,但是我们从它的子类ImageVIEwTarget中发现了onResourceReady方法,从这里我们继续往下看。
23、ImageVIEwTarget#onResourceReady
public abstract class ImageVIEwTarget<Z> extends VIEwTarget<ImageVIEw, Z>implements Transition.VIEwAdapter { ... @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) { // Order matters here. Set the resource first to make sure that the Drawable has a valID and // non-null Callback before starting it. // 核心代码 setResource(resource); maybeUpdateAnimatable(resource); } // 核心代码 protected abstract voID setResource(@Nullable Z resource);}复制代码
这里我们在回到BitmAPImageVIEwTarget的setResource方法中,我们终于看到Bitmap被设置到了当前的imageVIEw上了。
public class BitmAPImageVIEwTarget extends ImageVIEwTarget<Bitmap> { ... @OverrIDe protected voID setResource(Bitmap resource) { vIEw.setimageBitmap(resource); }}复制代码
到这里,我们的分析就结束了,从以上的分析可知,GlIDe将大部分的逻辑处理都放在了最后一个into方法中,里面经过了20多个分析步骤才将请求图片流、解码出图片,到最终设置到对应的imageVIEw上。
最后,这里给出一份我花费了数个小时绘制的完整GlIDe加载流程图,非常珍贵,大家可以仔仔细细再把GlIDe的主体流程在梳理一遍。
五、总结到此,GlIDe整个的加载流程分析就结束了,可以看到,GlIDe最核心的逻辑都聚集在into()方法中,它里面的设计精巧而复杂,这部分的源码分析非常耗时,但是,如果你真真正正地去一步步去深入其中,你也许在AndroID进阶之路上将会有顿悟的感觉。
链接:https://juejin.cn/post/6844904049595121672
以上是内存溢出为你收集整理的Android主流三方库源码分析(三、深入理解Glide源码)全部内容,希望文章能够帮你解决Android主流三方库源码分析(三、深入理解Glide源码)所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)