内容简介:Glide最基本的使用流程就是下面这行代码,其它所有扩展的额外功能都是以其建造者链式调用的基础上增加的。其中的GlideApp是注解处理器自动生成的,要使用GlideApp,必须先配置应用的AppGlideModule模块,里面可以为空配置,也可以根据实际情况添加指定配置。这里总结一下,对于当前传入的context是application或当前线程是子线程时,请求的生命周期和ApplicationLifecycle关联,否则,context是FragmentActivity或Fragment时,在当前组件添
Glide最基本的使用流程就是下面这行代码,其它所有扩展的额外功能都是以其建造者链式调用的基础上增加的。
GlideApp.with(context).load(url).into(iv); 复制代码
其中的GlideApp是注解处理器自动生成的,要使用GlideApp,必须先配置应用的AppGlideModule模块,里面可以为空配置,也可以根据实际情况添加指定配置。
@GlideModule public 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));--> } } 复制代码
GlideApp.with(context)
GlideApp#with
return (GlideRequests) Glide.with(context); 复制代码
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.getRequestManagerFactory() : null; builder.setRequestManagerFactory(factory); //配置manifest的属性 for (com.bumptech.glide.module.GlideModule module : manifestModules) { module.applyOptions(applicationContext, builder); } //配置注解生成类的属性 if (annotationGeneratedModule != null) { annotationGeneratedModule.applyOptions(applicationContext, 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(applicationContext, glide, glide.registry); } applicationContext.registerComponentCallbacks(glide); Glide.glide = glide; } 复制代码
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); } 复制代码
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); } 复制代码
RequestManagerRetriever#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)) { // 如果当前线程是主线程且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)。
为什么要使用注解生成的GlideApp
ApplicationLifecycle,SupportRequestManagerFragment,RequestManagerFragment 如何跟踪请求生命周期
load(url)
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); @NonNull private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) { // model则为设置的url this.model = model; // 记录url已设置 isModelSet = true; return this; } 复制代码
load这部分的源码很简单,就是给GlideRequest(RequestManager)设置了要请求的mode(url),并记录了url已设置的状态。
into(iv)
RequestBuilder.into
@NonNull public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) { Util.assertMainThread(); Preconditions.checkNotNull(view); RequestOptions requestOptions = this.requestOptions; if (!requestOptions.isTransformationSet() && requestOptions.isTransformationAllowed() && view.getScaleType() != null) { // Clone in this method so that if we use this RequestBuilder to load into a View and then // into a different target, we don't retain the transformation applied based on the previous // View's scale type. switch (view.getScaleType()) { // 这个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); } 复制代码
GlideContext#buildImageViewTarget
return imageViewTargetFactory.buildTarget(imageView, transcodeClass); 复制代码
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。
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; } // 分析1 private Request buildRequest( Target<TranscodeType> target, @Nullable RequestListener<TranscodeType> targetListener, RequestOptions requestOptions) { return buildRequestRecursive( target, targetListener, /*parentCoordinator=*/ null, transitionOptions, requestOptions.getPriority(), requestOptions.getOverrideWidth(), requestOptions.getOverrideHeight(), requestOptions); } // 分析1 private Request buildRequestRecursive( Target<TranscodeType> target, @Nullable RequestListener<TranscodeType> targetListener, @Nullable RequestCoordinator parentCoordinator, TransitionOptions<?, ? super TranscodeType> transitionOptions, Priority priority, int overrideWidth, int overrideHeight, RequestOptions requestOptions) { // Build the ErrorRequestCoordinator first if necessary so we can update parentCoordinator. ErrorRequestCoordinator errorRequestCoordinator = null; if (errorBuilder != null) { // 创建errorRequestCoordinator(异常处理对象) 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; } // 分析1 private 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)方法。
RequestManager#track
// 分析2 void track(@NonNull Target<?> target, @NonNull Request request) { // 加入一个target目标集合(Set) targetTracker.track(target); requestTracker.runRequest(request); } 复制代码
RequestTracker#runRequest
// 分析2 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"); } // 否则清空请求,加入延迟请求队列(为了对这些请求维持一个强引用,使用了ArrayList实现) pendingRequests.add(request); } } 复制代码
SingleRequest#begin
// 分析2 @Override public void begin() { ... if (model == null) { ... // model(url)为空,回调加载失败 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(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,可以猜到(因为后面只做了预加载缩略图的处理),真正的请求就是从这里开始的。
SingleRequest#onSizeReady
// 分析2 @Override public 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.getUseUnlimitedSourceGeneratorsPool(), requestOptions.getUseAnimationPool(), requestOptions.getOnlyRetrieveFromCache(), this); ... } 复制代码
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。
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); } } 复制代码
SourceGenerator#startNext
// 关注点2 @Override public 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().isDataCacheable(loadData.fetcher.getDataSource()) || helper.hasLoadPath(loadData.fetcher.getDataClass()))) { started = true; // 关注点6 通过loadData对象的fetcher对象(有关注点3的分析可知其实现类为HttpUrlFetcher)的 // loadData方法来获取图片数据 loadData.fetcher.loadData(helper.getPriority(), this); } } return started; } 复制代码
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; } 复制代码
HttpGlideUrlLoader#buildLoadData
@Override public 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)); } // 关注点5 public 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的时间。
HttpUrlFetcher#loadData
@Override public 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()方法获取到了最终的图片流。
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 { LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass()); // 核心代码 // 将解码任务分发给LoadPath return runLoadPath(data, dataSource, path); } private <Data, ResourceType> Resource<R> runLoadPath(Data data, DataSource dataSource, LoadPath<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. // 核心代码 // 将解码任务分发给LoadPath return path.load( rewinder, options, width, height, new DecodeCallback<ResourceType>(dataSource)); } finally { rewinder.cleanup(); } } 复制代码
LoadPath#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; } 复制代码
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); } @NonNull private 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); } } @NonNull private 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它会有不同的实现类,这里的实现类是ByteBufferBitmapDecoder,接下来让我们来看看这个解码器内部的解码流程。
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,它是一个压缩器,主要是对流进行解码,压缩,圆角等处理。
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对象进行了发布。
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 { ... } 复制代码
EngineJob#onResourceReady
@Override public 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这个方法。
@Synthetic void 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方法。
SingleRequest#onResourceReady
/** * A callback method that should never be invoked directly. */ @SuppressWarnings("unchecked") @Override public 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,看到ImageViewTarget类,我们并没有发现onResourceReady方法,但是我们从它的子类ImageViewTarget中发现了onResourceReady方法,从这里我们继续往下看。
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); } } 复制代码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- SpringCache框架加载/拦截原理
- Glide 图片加载框架源码解析
- 自定义MVC框架-自动加载类
- 优雅地实现Android主流图片加载框架封装,可无侵入切换框架
- SDWebImage 4.3.1 发布,iOS 图片加载框架
- golang iris mvc框架的服务端加载过程
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
CSS商业网站布局之道
朱印宏 / 清华大学出版社 / 2007-1 / 75.00元
本书是一本CSS技术专著。 主要从布局角度全面、系统和深入地讲解CSS在标准网站布局之中的应用。很多读者经过初步的学习之后就能够使用CSS设计出一些漂亮的网页样式,于是便乐在其中,踌躇满志,这是好事,但千万不要自我陶醉,因为你还未领略CSS的博大精深。用CSS容易,难的是全部都用CSS。CSS的精髓是布局,而不是样式,布局是需要缜密的逻辑思维和系统设计的,而样式只需要简单地编写代码或复制即可。本书......一起来看看 《CSS商业网站布局之道》 这本书的介绍吧!