<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                [TOC] 前兩篇我們詳細地分析了Android的網絡底層框架OKHttp和封裝框架Retrofit的核心源碼,如果對OKHttp或Retrofit內部機制不了解的可以看看[Android主流三方庫源碼分析(一、深入理解OKHttp源碼)](https://juejin.im/post/5e1be39b6fb9a02fcd130d1f)和[Android主流三方庫源碼分析(二、深入理解Retrofit源碼)](https://juejin.im/post/5e1fb9386fb9a0300a4501a6)。本篇,我們將會來深入地分析下目前Android使用最廣泛的圖片加載框架框架Glide的源碼加載流程。 ### 一、基本使用流程 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));--> } } ~~~ 接下來,本文將針對Glide的最新源碼版本V4.8.0對Glide加載網絡圖片的流程進行詳細地分析與講解,力爭做到讓讀者朋友們知其然也知其所以然。 ### 二、GlideApp.with(context)源碼詳解 首先,用**艽野塵夢**繪制的這份Glide框架圖讓我們對Glide的總體框架有一個初步的了解。 ![](https://img.kancloud.cn/06/39/06398999d7bcc6e4e2a56c52f28335b4_961x895.jpg) 從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 ~~~ @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)。 #### 6、GlideApp#with小結 ##### 1、初始化各式各樣的配置信息(包括緩存,請求線程池,大小,圖片格式等等)以及glide對象。 ##### 2、將glide請求和application/SupportFragment/Fragment的生命周期綁定在一塊。 ##### 這里我們再回顧一下with方法的執行流程。 ![](https://img.kancloud.cn/73/a9/73a9d225405fd4fe374ad84fcb324701_849x732.jpg) ### 三、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); @NonNull private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) { // model則為設置的url this.model = model; // 記錄url已設置 isModelSet = true; return this; } ~~~ 可以看到,load這部分的源碼很簡單,就是給GlideRequest(RequestManager)設置了要請求的mode(url),并記錄了url已設置的狀態。 ##### 這里,我們再看看load方法的執行流程。 ![](https://img.kancloud.cn/29/19/2919059b2da45a56175a53861a4b8730_749x575.jpg) ### 四、into(iv)源碼詳解 前方預警,真正復雜的地方開始了。 #### 1、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); } ~~~ #### 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; } // 分析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)方法,接著看看track里面做了什么。 #### 5、RequestManager#track ~~~ // 分析2 void track(@NonNull Target<?> target, @NonNull Request request) { // 加入一個target目標集合(Set) targetTracker.track(target); requestTracker.runRequest(request); } ~~~ #### 6、RequestTracker#runRequest ~~~ /** * Starts tracking the given request. */ // 分析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); } } ~~~ #### 7、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,可以猜到(因為后面只做了預加載縮略圖的處理),真正的請求就是從這里開始的,咱們進去一探究竟~ #### 8、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.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 @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().isDataCache able(loadData.fetcher.getDataSource()) || helper.hasLoadPath(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 ~~~ @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的時間。 #### 14、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()方法獲取到了最終的圖片流。 #### 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 { 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(); } } ~~~ #### 16、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; } ~~~ #### 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); } @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,接下來讓我們來看看這個解碼器內部的解碼流程。 #### 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 ~~~ @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方法。 #### 22、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,看到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的主體流程在梳理一遍。 ![](https://img.kancloud.cn/2b/bd/2bbd0a3e4594c2a0835df42d2cc09986_511x1280.jpg) ### 五、總結 到此,Glide整個的加載流程分析就結束了,可以看到,Glide最核心的邏輯都聚集在into()方法中,它里面的設計精巧而復雜,這部分的源碼分析非常耗時,但是,如果你真真正正地去一步步去深入其中,你也許在Android進階之路上將會有頓悟的感覺。目前,Android主流三方庫源碼分析系列已經對網絡庫(OkHttp、Retrofit)和圖片加載庫(Glide)進行了詳細的源碼分析,接下來,將會對數據庫框架GreenDao的核心源碼進行深入的分析,敬請期待~ ##### 參考鏈接: * * * 1、Glide V4.8.0源碼 2、[從源碼的角度理解Glide的執行流程](https://blog.csdn.net/guolin_blog/article/details/53939176) 3、[glide源碼分析](https://zhuanlan.zhihu.com/p/37297719) 鏈接:https://juejin.im/post/5e2109e25188254c257c40c6
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看