简介
Glide 作为Android开发过程中常见的图片加载工具,在我们日常开发中用到到越来越多.但是个人也只是停留在用的状态.最近时间充裕简单的梳理了一下Glide 加载网络图的流程
流程
1.1 Glide.with(content) 得到RequestManagerRetriever初始化了RequestManager和Glide.
@NonNullpublic static RequestManager with(@NonNull Context context) { //etRetriever() 获取RequestManagerRetriever return getRetriever(context).get(context);} @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)) { 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()); } } return getApplicationManager(context);}Glide.with(context) --> (RequestManagerRetriever)getRetriever(context).get(context)-->(RequestManagerRetriever)getApplicationManager(context){ //初始化 Glide Glide glide = Glide.get(context.getApplicationContext()); //初始化 RequestManager applicationManager = factory.build( glide, new ApplicationLifecycle(), new EmptyRequestManagerTreeNode(), context.getApplicationContext()); }}//创建 RequestManager public interface RequestManagerFactory { @NonNull RequestManager build( @NonNull Glide glide, @NonNull Lifecycle lifecycle, @NonNull RequestManagerTreeNode requestManagerTreeNode, @NonNull Context context);}//创建 RequestManagerprivate static final RequestManagerFactory DEFAULT_FACTORY = new RequestManagerFactory() { @NonNull @Override public RequestManager build(@NonNull Glide glide, @NonNull Lifecycle lifecycle, @NonNull RequestManagerTreeNode requestManagerTreeNode, @NonNull Context context) { return new RequestManager(glide, lifecycle, requestManagerTreeNode, context); }};}1.2 Glide.get(context.getApplicationContext())
Glide.get(context.getApplicationContext()) -->checkAndInitializeGlide(context) -->initializeGlide(...)-->(GlideBuilder)builder.build(applicationContext)-->public Glide build(@NonNull Context context) { //初始化 Glide ... //注意这个要用 初始化了 下边要用的 (RequestManagerFactory)factory RequestManagerRetriever requestManagerRetriever =new RequestManagerRetriever(requestManagerFactory); return new Glide(.....)}2.0 Glide.with(context).load() 的load方法
load()方法默认是 asRrawable()类型,用来初始化RequestBuilder 和 loadGeneric()方法初始化model(地址)
注意
这里体现了 asBitmap()和asDrawable() 方法必须放在load()前边的原因
//as方法@NonNull@CheckResult@Overridepublic RequestBuilder<Drawable> load(@Nullable String string) { return asDrawable().load(string);}@NonNull@CheckResultpublic RequestBuilder<Drawable> asDrawable() { return as(Drawable.class);}//(重要) 创建了 RequestBuilder 且 默认传入的 resourceClass 是 Drawable.class)//返回 获取target DrawableImageViewTarget @NonNull@CheckResultpublic <ResourceType> RequestBuilder<ResourceType> as( @NonNull Class<ResourceType> resourceClass) { return new RequestBuilder<>(glide, this, resourceClass, context);}//设置加载的内容(地址或者资源 ) /*** Sets the specific model to load data for.** @param model The model to load data for, or null.* @return This request builder.*/@NonNull@CheckResult@SuppressWarnings("unchecked")@Overridepublic RequestBuilder<TranscodeType> load(@Nullable Object model) { return loadGeneric(model);}@NonNullprivate RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) { this.model = model; isModelSet = true; return this;}3.Glide 的into() 资源选择以及下载都在这里这里重点分析
1.调用into方法()
//调用into()方法 @NonNullpublic ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) { Util.assertMainThread(); Preconditions.checkNotNull(view); //设置 RequestOptions 参数 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()) { 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. } } //获取 ViewTarget 类型 默认得到DrawableImageViewTarget 因为load方法默认调用 asDrawable() glideContext.buildImageViewTarget(view, transcodeClass) return into( glideContext.buildImageViewTarget(view, transcodeClass), /*targetListener=*/ null, requestOptions);}//继续调用 private <Y extends Target<TranscodeType>> Y into( @NonNull Y target, @Nullable RequestListener<TranscodeType> targetListener, @NonNull RequestOptions options) { //判断主线程 Preconditions.checkNotNull(target); if (!isModelSet) { throw new IllegalArgumentException("You must call #load() before calling #into()"); } options = options.autoClone(); //构建请求 核心方法 Request request = buildRequest(target, targetListener, options); Request previous = target.getRequest(); if (request.isEquivalentTo(previous) && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) { request.recycle(); if (!Preconditions.checkNotNull(previous).isRunning()) { previous.begin(); } return target; } requestManager.clear(target); target.setRequest(request); requestManager.track(target, request); return target;}1.2.构建请求(RequestBuilder 请求构建类)
// 调用构建请求RequestBuilder 的构建方法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);}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 = new ErrorRequestCoordinator(parentCoordinator); parentCoordinator = errorRequestCoordinator; } //执行构建主要的请求 Request mainRequest = buildThumbnailRequestRecursive( target, targetListener, parentCoordinator, transitionOptions, priority, overrideWidth, overrideHeight, requestOptions); if (errorRequestCoordinator == null) { return mainRequest; } int errorOverrideWidth = errorBuilder.requestOptions.getOverrideWidth(); int errorOverrideHeight = errorBuilder.requestOptions.getOverrideHeight(); if (Util.isValidDimensions(overrideWidth, overrideHeight) && !errorBuilder.requestOptions.isValidOverride()) { errorOverrideWidth = requestOptions.getOverrideWidth(); errorOverrideHeight = requestOptions.getOverrideHeight(); } Request errorRequest = errorBuilder.buildRequestRecursive( target, targetListener, errorRequestCoordinator, errorBuilder.transitionOptions, errorBuilder.requestOptions.getPriority(), errorOverrideWidth, errorOverrideHeight, errorBuilder.requestOptions); errorRequestCoordinator.setRequests(mainRequest, errorRequest); return errorRequestCoordinator;} //执行构建主要的请求 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. if (isThumbnailBuilt) { throw new IllegalStateException("You cannot use a request as both the main request and a " + "thumbnail, consider using clone() on the request(s) passed to thumbnail()"); } TransitionOptions<?, ? super TranscodeType> thumbTransitionOptions = thumbnailBuilder.transitionOptions; // Apply our transition by default to thumbnail requests but avoid overriding custom options // that may have been applied on the thumbnail request explicitly. if (thumbnailBuilder.isDefaultTransitionOptionsSet) { thumbTransitionOptions = transitionOptions; } Priority thumbPriority = thumbnailBuilder.requestOptions.isPrioritySet() ? thumbnailBuilder.requestOptions.getPriority() : getThumbnailPriority(priority); int thumbOverrideWidth = thumbnailBuilder.requestOptions.getOverrideWidth(); int thumbOverrideHeight = thumbnailBuilder.requestOptions.getOverrideHeight(); if (Util.isValidDimensions(overrideWidth, overrideHeight) && !thumbnailBuilder.requestOptions.isValidOverride()) { thumbOverrideWidth = requestOptions.getOverrideWidth(); thumbOverrideHeight = requestOptions.getOverrideHeight(); } 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.setRequests(fullRequest, thumbRequest); return coordinator; } else if (thumbSizeMultiplier != null) { // Base case: thumbnail multiplier generates a thumbnail request, but cannot recurse. 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) { return SingleRequest.obtain( context, glideContext, model, transcodeClass, requestOptions, overrideWidth, overrideHeight, priority, target, targetListener, requestListener, requestCoordinator, glideContext.getEngine(), transitionOptions.getTransitionFactory());}// SingleRequest 单例请求类 public static <R> SingleRequest<R> obtain( Context context, GlideContext glideContext, Object model, Class<R> transcodeClass, RequestOptions requestOptions, int overrideWidth, int overrideHeight, Priority priority, Target<R> target, RequestListener<R> targetListener, RequestListener<R> requestListener, RequestCoordinator requestCoordinator, Engine engine, TransitionFactory<? super R> animationFactory) { @SuppressWarnings("unchecked") SingleRequest<R> request = (SingleRequest<R>) POOL.acquire(); if (request == null) { request = new SingleRequest<>(); } request.init( context, glideContext, model, transcodeClass, requestOptions, overrideWidth, overrideHeight, priority, target, targetListener, requestListener, requestCoordinator, engine, animationFactory); return request;}//初始化单例 请求rivate void init( Context context, GlideContext glideContext, Object model, Class<R> transcodeClass, RequestOptions requestOptions, int overrideWidth, int overrideHeight, Priority priority, Target<R> target, RequestListener<R> targetListener, RequestListener<R> requestListener, RequestCoordinator requestCoordinator, Engine engine, TransitionFactory<? super R> animationFactory) { this.context = context; this.glideContext = glideContext; this.model = model; this.transcodeClass = transcodeClass; this.requestOptions = requestOptions; this.overrideWidth = overrideWidth; this.overrideHeight = overrideHeight; this.priority = priority; this.target = target; this.targetListener = targetListener; this.requestListener = requestListener; this.requestCoordinator = requestCoordinator; this.engine = engine; this.animationFactory = animationFactory; status = Status.PENDING;}1.3 开启请求
private <Y extends Target<TranscodeType>> Y into( @NonNull Y target, @Nullable RequestListener<TranscodeType> targetListener, @NonNull RequestOptions options) { //判断主线程 Preconditions.checkNotNull(target); if (!isModelSet) { throw new IllegalArgumentException("You must call #load() before calling #into()"); } options = options.autoClone(); //构建请求 只是做了个初始化的操作 Request request = buildRequest(target, targetListener, options); // 返回这个Target 上边的请求 因为上边是做初始化操作所以 第一次这个previous 请求是null // request.isEquivalentTo(previous) =false Request previous = target.getRequest(); if (request.isEquivalentTo(previous) && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) { request.recycle(); if (!Preconditions.checkNotNull(previous).isRunning()) { //开启请求 previous.begin(); } return target; } requestManager.clear(target); //给target设置上请求 target.setRequest(request); //开启 请求(正常情况下走这个) requestManager.track(target, request); return target;} void track(Target<?> target, Request request) { targetTracker.track(target); requestTracker.runRequest(request);}public void runRequest(Request request) { requests.add(request); // 我的Demo是在 Activity 中展示所以isPaused()是true 所以是否执行请求是根据生命周期走的 if (!isPaused) { request.begin(); } else { pendingRequests.add(request); }}查了一下代码 因为 RequestManager 实现了 LifecycleListener 监听了页面的生命周期 所以 RequestManager中实现了 onStart 方法 resumeRequests 调用了resumeRequests()@Overridepublic void onStart() { resumeRequests(); targetTracker.onStart();} //页面展示开启请求public void resumeRequests() { isPaused = false; for (Request request : Util.getSnapshot(requests)) { if (!request.isComplete() && !request.isCancelled() && !request.isRunning()) { request.begin(); } } pendingRequests.clear();}//上边是请求执行了1.4 SingleRequest 单例请求的代码
public static <R> SingleRequest<R> obtain( Context context, GlideContext glideContext, Object model, Class<R> transcodeClass, RequestOptions requestOptions, int overrideWidth, int overrideHeight, Priority priority, Target<R> target, RequestListener<R> targetListener, RequestListener<R> requestListener, RequestCoordinator requestCoordinator, Engine engine, TransitionFactory<? super R> animationFactory) { @SuppressWarnings("unchecked") SingleRequest<R> request = (SingleRequest<R>) POOL.acquire(); if (request == null) { request = new SingleRequest<>(); } request.init( context, glideContext, model, transcodeClass, requestOptions, overrideWidth, overrideHeight, priority, target, targetListener, requestListener, requestCoordinator, engine, animationFactory); return request;}@SuppressWarnings("WeakerAccess")@SyntheticSingleRequest() { // just create, instances are reused with recycle/init}//初始化了请求的数据private void init( Context context, GlideContext glideContext, Object model, Class<R> transcodeClass, RequestOptions requestOptions, int overrideWidth, int overrideHeight, Priority priority, Target<R> target, RequestListener<R> targetListener, RequestListener<R> requestListener, RequestCoordinator requestCoordinator, Engine engine, TransitionFactory<? super R> animationFactory) { this.context = context; this.glideContext = glideContext; this.model = model; this.transcodeClass = transcodeClass; this.requestOptions = requestOptions; this.overrideWidth = overrideWidth; this.overrideHeight = overrideHeight; this.priority = priority; this.target = target; this.targetListener = targetListener; this.requestListener = requestListener; this.requestCoordinator = requestCoordinator; this.engine = engine; this.animationFactory = animationFactory; status = Status.PENDING;}//开启了请求 @Overridepublic void begin() { assertNotCallingCallbacks(); stateVerifier.throwIfRecycled(); startTime = LogTime.getLogTime(); // model 就是load() 传入的地址或者资源数据 为空直接走了 错误的回调然后直接返回 if (model == null) { if (Util.isValidDimensions(overrideWidth, overrideHeight)) { width = overrideWidth; height = overrideHeight; } 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; } // Restarts for requests that are neither complete nor running can be treated as new requests // and can run again from the beginning. status = Status.WAITING_FOR_SIZE; // 判断图片的宽高 有宽高证明存在直接展示 if (Util.isValidDimensions(overrideWidth, overrideHeight)) { onSizeReady(overrideWidth, overrideHeight); } else { //重要 执行了获取宽高的方法 因为实现了SizeReadyCallback接口 执行 onSizeReady() 方法 //DrawableImageViewTarget --> ViewTarget --> getSize(SizeReadyCallback cb) //{ cb.onSizeReady(currentWidth, currentHeight);} target.getSize(this); } if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE) && canNotifyStatusChanged()) { //开始加载 getPlaceholderDrawable() 获取占位图 target.onLoadStarted(getPlaceholderDrawable()); } if (IS_VERBOSE_LOGGABLE) { logV("finished run method in " + LogTime.getElapsedMillis(startTime)); }}1.5 Engine 下载图片
@Overridepublic void onSizeReady(int width, int height) { stateVerifier.throwIfRecycled(); if (IS_VERBOSE_LOGGABLE) { logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime)); } if (status != Status.WAITING_FOR_SIZE) { return; } status = Status.RUNNING; float sizeMultiplier = requestOptions.getSizeMultiplier(); this.width = maybeApplySizeMultiplier(width, sizeMultiplier); this.height = maybeApplySizeMultiplier(height, sizeMultiplier); if (IS_VERBOSE_LOGGABLE) { logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime)); } // Engine 负责启动负载并管理活动和缓存的资源 // 加载资源 监听是 ResourceCallback 实现方法 onResourceReady 加载准备 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); // This is a hack that's only useful for testing right now where loads complete synchronously // even though under any executor running on any thread but the main thread, the load would // have completed asynchronously. if (status != Status.RUNNING) { loadStatus = null; } if (IS_VERBOSE_LOGGABLE) { logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime)); }// Engine 负责启动负载并管理活动和缓存的资源 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) { Util.assertMainThread(); long startTime = LogTime.getLogTime(); EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations, resourceClass, transcodeClass, options); //从活动资源加载资源 EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable); if (active != null) { cb.onResourceReady(active, DataSource.MEMORY_CACHE); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Loaded resource from active resources", startTime, key); } return null; }//加载缓存资源 EngineResource<?> cached = loadFromCache(key, isMemoryCacheable); if (cached != null) { cb.onResourceReady(cached, DataSource.MEMORY_CACHE); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Loaded resource from cache", startTime, key); } return null; } //当前加载网络资源 (同请求加载重新请求的资源)) EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache); if (current != null) { current.addCallback(cb); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Added to existing load", startTime, key); } return new LoadStatus(cb, current); } 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.put(key, engineJob); //增加监听 engineJob.addCallback(cb); //启动加载 engineJob.start(decodeJob); if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Started new load", startTime, key); } return new LoadStatus(cb, engineJob);}// 开启异步加载数据 public void start(DecodeJob<R> decodeJob) { this.decodeJob = decodeJob; GlideExecutor executor = decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor(); //开始加载 executor.execute(decodeJob);} 1.6 DecodeJob下载的线程(重要)
@Overridepublic void run() { TraceCompat.beginSection("DecodeJob#run"); DataFetcher<?> localFetcher = currentFetcher; try { //是否取消请求 if (isCancelled) { notifyFailed(); return; } //运行 runWrapped(); } catch (Throwable t) { // Catch Throwable and not Exception to handle OOMs. Throwables are swallowed by our // usage of .submit() in GlideExecutor so we're not silently hiding crashes by doing this. We // are however ensuring that our callbacks are always notified when a load fails. Without this // notification, uncaught throwables never notify the corresponding callbacks, which can cause // loads to silently hang forever, a case that's especially bad for users using Futures on // background threads. if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "DecodeJob threw unexpectedly" + ", isCancelled: " + isCancelled + ", stage: " + stage, t); } // When we're encoding we've already notified our callback and it isn't safe to do so again. if (stage != Stage.ENCODE) { throwables.add(t); notifyFailed(); } if (!isCancelled) { throw t; } } finally { // Keeping track of the fetcher here and calling cleanup is excessively paranoid, we call // close in all cases anyway. if (localFetcher != null) { localFetcher.cleanup(); } TraceCompat.endSection(); }} //运行选择的处理()会循环执行 去判断三级资源 先资源判断 再缓存半段 再下载private void runWrapped() { switch (runReason) { // The first time we've been submitted. 第一次请求 case INITIALIZE: //获取资源的类型(初始阶段) stage = getNextStage(Stage.INITIALIZE); //获取一个资源生成器 currentGenerator = getNextGenerator(); runGenerators(); break; //从缓存处理 case SWITCH_TO_SOURCE_SERVICE: runGenerators(); break; //我们在一个我们不拥有的线程上检索了一些数据,并希望切换回我们的线程 case DECODE_DATA: decodeFromRetrievedData(); break; default: throw new IllegalStateException("Unrecognized run reason: " + runReason); }} //判断资源的类型 缓存 还是资源文件private DataFetcherGenerator getNextGenerator() { switch (stage) { case RESOURCE_CACHE: return new ResourceCacheGenerator(decodeHelper, this); case DATA_CACHE: return new DataCacheGenerator(decodeHelper, this); case SOURCE: //下载走这里 return new SourceGenerator(decodeHelper, this); case FINISHED: return null; default: throw new IllegalStateException("Unrecognized stage: " + stage); }}//执行 数据判断(会循环上掉直到找到数据) HttpUrlFetcher 没缓存走下载 private void runGenerators() { currentThread = Thread.currentThread(); startFetchTime = LogTime.getLogTime(); boolean isStarted = false; //currentGenerator.startNext() 执行找数据 while (!isCancelled && currentGenerator != null && !(isStarted = currentGenerator.startNext())) { stage = getNextStage(stage); currentGenerator = getNextGenerator(); if (stage == Stage.SOURCE) { reschedule(); return; } } // We've run out of stages and generators, give up. if ((stage == Stage.FINISHED || isCancelled) && !isStarted) { notifyFailed(); } // Otherwise a generator started a new load and we expect to be called back in // onDataFetcherReady.} @Overridepublic boolean startNext() { 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()) { loadData = helper.getLoadData().get(loadDataListIndex++); if (loadData != null && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource()) || helper.hasLoadPath(loadData.fetcher.getDataClass()))) { started = true; loadData.fetcher.loadData(helper.getPriority(), this); } } return started;}1.7 下载\
//HttpUrlFetcher //* A DataFetcher that retrieves an {@link java.io.InputStream} for a Url. @Override public boolean startNext() { 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()) { loadData = helper.getLoadData().get(loadDataListIndex++); if (loadData != null && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource()) || helper.hasLoadPath(loadData.fetcher.getDataClass()))) { started = true; loadData.fetcher.loadData(helper.getPriority(), this); } } return started; } // 图片下载 @Override public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) { long startTime = LogTime.getLogTime(); try { // callback SourceGenerator 实现了 DataFetcher.DataCallback<Object> 接口 回调到 SourceGenerator InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders()); callback.onDataReady(result); } catch (IOException e) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "Failed to load data for url", e); } //FetcherReadyCallback 下载回调 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 { if (redirects >= MAXIMUM_REDIRECTS) { throw new HttpException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!"); } else { // Comparing the URLs using .equals performs additional network I/O and is generally broken. // See http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html. try { if (lastUrl != null && url.toURI().equals(lastUrl.toURI())) { throw new HttpException("In re-direct loop"); } } catch (URISyntaxException e) { // Do nothing, this is best effort. } } urlConnection = connectionFactory.build(url); for (Map.Entry<String, String> headerEntry : headers.entrySet()) { urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue()); } urlConnection.setConnectTimeout(timeout); urlConnection.setReadTimeout(timeout); urlConnection.setUseCaches(false); urlConnection.setDoInput(true); // Stop the urlConnection instance of HttpUrlConnection from following redirects so that // redirects will be handled by recursive calls to this method, loadDataWithRedirects. urlConnection.setInstanceFollowRedirects(false); // Connect explicitly to avoid errors in decoders if connection fails. urlConnection.connect(); // Set the stream so that it's closed in cleanup to avoid resource leaks. See #2352. stream = urlConnection.getInputStream(); if (isCancelled) { return null; } final int statusCode = urlConnection.getResponseCode(); if (isHttpOk(statusCode)) { return getStreamForSuccessfulRequest(urlConnection); } else if (isHttpRedirect(statusCode)) { String redirectUrlString = urlConnection.getHeaderField("Location"); if (TextUtils.isEmpty(redirectUrlString)) { throw new HttpException("Received empty or null redirect url"); } URL redirectUrl = new URL(url, redirectUrlString); // Closing the stream specifically is required to avoid leaking ResponseBodys in addition // to disconnecting the url connection below. See #2352. cleanup(); return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers); } else if (statusCode == INVALID_STATUS_CODE) { throw new HttpException(statusCode); } else { throw new HttpException(urlConnection.getResponseMessage(), statusCode); } } 1.8 回调
// 的回调到 SourceGenerator onDataReady @Override public void onDataReady(Object data) { DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy(); if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) { dataToCache = data; // We might be being called back on someone else's thread. Before doing anything, we should // reschedule to get back onto Glide's thread. cb.reschedule(); } else { cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher, loadData.fetcher.getDataSource(), originalKey); } } // 因为 DecodeJob 实现了 FetcherReadyCallback 接口 且 SourceGenerator(this) 是这么创建的 //所以回调到 DecodeJob 的 onDataFetcherReady方法 @Override public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) { // This data fetcher will be loading from a File and provide the wrong data source, so override // with the data source of the original fetcher // cb 是 DecodeJob cb.onDataFetcherReady(sourceKey, data, fetcher, loadData.fetcher.getDataSource(), sourceKey); } // DecodeJob 的 onDataFetcherReady @Override public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) { this.currentSourceKey = sourceKey; this.currentData = data; this.currentFetcher = fetcher; this.currentDataSource = dataSource; this.currentAttemptingKey = attemptedKey; if (Thread.currentThread() != currentThread) { runReason = RunReason.DECODE_DATA; callback.reschedule(this); } else { TraceCompat.beginSection("DecodeJob.decodeFromRetrievedData"); try { //数解码(处理下载的数据) decodeFromRetrievedData(); } finally { TraceCompat.endSection(); } } } 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) { notifyEncodeAndRelease(resource, currentDataSource); } else { runGenerators(); } } //通知 private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) { if (resource instanceof Initializable) { ((Initializable) resource).initialize(); } Resource<R> result = resource; LockedResource<R> lockedResource = null; if (deferredEncodeManager.hasResourceToEncode()) { lockedResource = LockedResource.obtain(resource); result = lockedResource; } //下载完成通知填充页面 notifyComplete(result, dataSource); stage = Stage.ENCODE; try { if (deferredEncodeManager.hasResourceToEncode()) { deferredEncodeManager.encode(diskCacheProvider, options); } } finally { if (lockedResource != null) { lockedResource.unlock(); } } // Call onEncodeComplete outside the finally block so that it's not called if the encode process // throws. onEncodeComplete(); } private void notifyComplete(Resource<R> resource, DataSource dataSource) { setNotifiedOrThrow(); // callback 是传入的调用EngineJob 调用 EngineJob的onResourceReady方法 callback.onResourceReady(resource, dataSource); }//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(); }//状态的Handler private static final Handler MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper(), new MainThreadCallback()); private static class MainThreadCallback implements Handler.Callback { @Synthetic @SuppressWarnings("WeakerAccess") MainThreadCallback() { } @Override public boolean handleMessage(Message message) { EngineJob<?> job = (EngineJob<?>) message.obj; switch (message.what) { case MSG_COMPLETE: //完成的的通知 job.handleResultOnMainThread(); break; case MSG_EXCEPTION: job.handleExceptionOnMainThread(); break; case MSG_CANCELLED: job.handleCancelledOnMainThread(); break; default: throw new IllegalStateException("Unrecognized message: " + message.what); } return true; } } @Synthetic void handleResultOnMainThread() { stateVerifier.throwIfRecycled(); if (isCancelled) { resource.recycle(); release(false /*isRemovedFromQueue*/); return; } else if (cbs.isEmpty()) { throw new IllegalStateException("Received a resource without any callbacks to notify"); } else if (hasResource) { throw new IllegalStateException("Already have resource"); } engineResource = engineResourceFactory.build(resource, isCacheable); hasResource = true; // Hold on to resource for duration of request so we don't recycle it in the middle of // notifying if it synchronously released by one of the callbacks. engineResource.acquire(); listener.onEngineJobComplete(this, key, engineResource); //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是 SingleRequest 回调的单例请求onResourceReady 的方法 cb.onResourceReady(engineResource, dataSource); } } // Our request is complete, so we can release the resource. engineResource.release(); release(false /*isRemovedFromQueue*/); } // SingleRequest 单例请求 /** * A callback method that should never be invoked directly. */ @SuppressWarnings("unchecked") @Override public void onResourceReady(Resource<?> resource, DataSource dataSource) { stateVerifier.throwIfRecycled(); loadStatus = null; if (resource == null) { GlideException exception = new GlideException("Expected to receive a Resource<R> with an " + "object of " + transcodeClass + " inside, but instead got null."); onLoadFailed(exception); return; } Object received = resource.get(); if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) { releaseResource(resource); GlideException exception = new GlideException("Expected to receive an object of " + transcodeClass + " but instead" + " got " + (received != null ? received.getClass() : "") + "{" + received + "} inside" + " " + "Resource{" + resource + "}." + (received != null ? "" : " " + "To indicate failure return a null Resource " + "object, rather than a Resource object containing null data.")); onLoadFailed(exception); return; } if (!canSetResource()) { releaseResource(resource); // We can't put the status to complete before asking canSetResource(). status = Status.COMPLETE; return; } //资源准备好了 onResourceReady((Resource<R>) resource, (R) received, dataSource); } /** * Internal {@link #onResourceReady(Resource, DataSource)} where arguments are known to be safe. * * @param resource original {@link Resource}, never <code>null</code> * @param result object returned by {@link Resource#get()}, checked for type and never * <code>null</code> */ private void onResourceReady(Resource<R> resource, R result, DataSource dataSource) { // We must call isFirstReadyResource before setting status. boolean isFirstResource = isFirstReadyResource(); status = Status.COMPLETE; this.resource = resource; if (glideContext.getLogLevel() <= Log.DEBUG) { Log.d(GLIDE_TAG, "Finished loading " + result.getClass().getSimpleName() + " from " + dataSource + " for " + model + " with size [" + width + "x" + height + "] in " + LogTime.getElapsedMillis(startTime) + " ms"); } isCallingCallbacks = true; try { if ((requestListener == null || !requestListener.onResourceReady(result, model, target, dataSource, isFirstResource)) && (targetListener == null || !targetListener.onResourceReady(result, model, target, dataSource, isFirstResource))) { Transition<? super R> animation = animationFactory.build(dataSource, isFirstResource); //填充到页面 target 默认是DrawableImageViewTarget target.onResourceReady(result, animation); } } finally { isCallingCallbacks = false; } notifyLoadSuccess(); } //最后回调到DrawableImageViewTarget 的setResource() 方法 view是个ImagView @Override protected void setResource(@Nullable Drawable resource) { view.setImageDrawable(resource); } 总结
这里简单的梳理了Glide 第一次加载图片 从初始化到配置参数,然后判断是否有缓存再到下载完成然后通知展示的简单流程.源码中涉及到的回调比较多建议代码跟一下(特别注意生命周期的影响).
大致上代码流程是:
Glide.with()配置Glide 的一些参数 load() 配置请求的构建起 into()首先判断本子资源是否有然后缓存文件是否存在都没有就调用下载,下载完成通知展示.因为Glide RequestManager implements LifecycleListener 监听了页面的生命周期注意,一下生命周期对展示的影响
还有一些生命周期对Glide的影响,以及异常展示的流程没有处理,有兴趣的可以研究下 |