glide_logo.png
上两一篇文章从源码角度深入理解Glide(上)中,我们了解了Glide框架中的一些用法,并且分析了Glide的with方法和load方法,由于简书限制字数篇幅原因into方法留到本篇文章分析,废话不多说,接下来马上开始分析。
into方法
通过上一小节的分析,经过load方法之后获取的对象是RequestBuilder,并且我们将load方法的参数赋值给了RequestBuilder对象的model参数,接下来就到了Glide最核心的方法,也就是RequestBuilder对象的into方法
获取DrawableImageViewTarget
/** 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()) { 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. } } return into( glideContext.buildImageViewTarget(view, transcodeClass), /*targetListener=*/ null, requestOptions); }
RequestBuilder 对象的into方法中首先获取传递进来的ImageView的ScaleType,让Glide加载出来的ImageView保持一样的ScaleType变化,然后我们看到最后一句话,该方法返回了RequestBuilder 对象的另一个into方法,先看glideContext.buildImageViewTarget()做了什么操作
/** GlideContext 类的 buildImageViewTarget方法*/ @NonNull public <X> ViewTarget<ImageView, X> buildImageViewTarget( @NonNull ImageView imageView, @NonNull Class<X> transcodeClass) { return imageViewTargetFactory.buildTarget(imageView, transcodeClass); } public class ImageViewTargetFactory { @NonNull @SuppressWarnings("unchecked") public <Z> ViewTarget<ImageView, Z> buildTarget(@NonNull ImageView view, @NonNull Class<Z> clazz) { 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 { //省略代码 ..... } } }
通过以上源码,之前我们看RequestBuilder源码中as方法传入的是Drawable.class,所以以上的buildImageViewTarget方法最终返回的是DrawableImageViewTarget对象,接着我们继续看第一步into方法返回into方法中做了什么操作
构建Request
/** RequestBuilder 类的into方法返回的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(); Request request = buildRequest(target, targetListener, options); //省略部分代码 ...... requestManager.clear(target); target.setRequest(request); requestManager.track(target, request); return target; }
通过以上源码,我们应该先明白Request类是一个接口,他抽象了Glide加载图片请求(Request类源码这里就不贴了),它是一个非常重要的类,这里我们先看看buildRequest(target, targetListener, options)方法是如何创建Request对象的
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) { //省略部分代码 error Request build ..... Request mainRequest = buildThumbnailRequestRecursive( target, targetListener, parentCoordinator, transitionOptions, priority, overrideWidth, overrideHeight, requestOptions); if (errorRequestCoordinator == null) { return mainRequest; } //省略部分代码 error Request build ..... } 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) { //省略部分代码 缩略图操作 ..... } 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, requestListeners, requestCoordinator, glideContext.getEngine(), transitionOptions.getTransitionFactory()); }
通过上面的源码,我们可以看到buildRequest方法调用了buildRequestRecursive方法,在buildRequestRecursive方法中大部分代码都在处理缩略图(thumbnail),我们主流程中没有设置缩略图,这里就不进行展开分析,接着buildRequestRecursive方法又调用了obtainRequest方法,obtainRequest方法传递了非常多参数,比如有我们熟悉的RequestOptions,设置图片尺寸的 overrideWidth, overrideHeight,还有第一步into方法中的target对象,也就是DrawableImageViewTarget对象,model也就是我们load传入的图片地址,也就说明不管load方法还是apply方法传入的参数最终都给到了这里传入SingleRequest.obtain方法,我们继续看看SingleRequest类
public final class SingleRequest<R> implements Request, SizeReadyCallback, ResourceCallback, FactoryPools.Poolable {//省略部分代码....../**SingleRequest类的 obtain方法*/ 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, @Nullable List<RequestListener<R>> requestListeners, 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, requestListeners, requestCoordinator, engine, animationFactory); return request; } //省略部分代码 ...... }
通过SingleRequest对象的obtain方法,我们可以看到request = new SingleRequest<>();也就是最终我们构建的Request是SingleRequest对象,并在init方法中将上一步obtainRequest方法传递进来的各种参数进行赋值。
Request执行
构建完成Request对象,接下来继续看刚刚的into方法下面的操作
requestManager.clear(target);target.setRequest(request);requestManager.track(target, request);return target
首先RequestManager对象清除target,此时不懂你是否还记得RequestManager,该对象是第一步with方法之后得到的,接着是将我们上一步得到的SingleRequest对象设置给target,接着又执行了RequestManager.track方法,继续跟进该方法看看
/** RequestManager 类的track方法*/void track(@NonNull Target<?> target, @NonNull Request request) { targetTracker.track(target); requestTracker.runRequest(request); }/** RequestTracker 类的runRequest方法*/ private final List<Request> pendingRequests = new ArrayList<>(); 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"); } pendingRequests.add(request); } }
通过上面的源码,RequestManager对象的track方法中执行了RequestTracker 类的runRequest方法,该方法中简单判断当前Glide是否在暂停状态,不是暂停状态则执行Request的begin方法,否则将这个Request加入到请求队列List<Request>pendingRequests中.
后备回调符、加载占位符和错误占位符加载
接下来我们看看Request的begin方法到底干了啥,要找到begin方法实现,根据前面分析,我们则应该去看SingleRequest对象的begin方法
/** SingleRequest 类的begin方法*/ @Override public void begin() { assertNotCallingCallbacks(); stateVerifier.throwIfRecycled(); startTime = LogTime.getLogTime(); if (model == null) { if (Util.isValidDimensions(overrideWidth, overrideHeight)) { width = overrideWidth; height = overrideHeight; } int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG; 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)) { onSizeReady(overrideWidth, overrideHeight); } else { 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)); } } private void onLoadFailed(GlideException e, int maxLogLevel) { //省略部分代码 ....... if (!anyListenerHandledUpdatingTarget) { setErrorPlaceholder(); } //省略部分代码 ....... }
通过以上begin方法源码,如果model为空,也就是我们load传入的图片地址为空,则会调用onLoadFailed方法,而onLoadFailed方法又调用了setErrorPlaceholder方法,接着看看该方法中做了什么操作
/** SingleRequest 类的setErrorPlaceholder方法*/ private void setErrorPlaceholder() { if (!canNotifyStatusChanged()) { return; } Drawable error = null; if (model == null) { error = getFallbackDrawable(); } // Either the model isn't null, or there was no fallback drawable set. if (error == null) { error = getErrorDrawable(); } // The model isn't null, no fallback drawable was set or no error drawable was set. if (error == null) { error = getPlaceholderDrawable(); } target.onLoadFailed(error); } private Drawable getErrorDrawable() { if (errorDrawable == null) { errorDrawable = requestOptions.getErrorPlaceholder(); if (errorDrawable == null && requestOptions.getErrorId() > 0) { errorDrawable = loadDrawable(requestOptions.getErrorId()); } } return errorDrawable; }
通过以上源码,如果我们传入图片地址为空,则首先查看是否有后备回调符设置,然后是错误占位符,最后是加载占位符,最终调用target.onLoadFailed方法,也就是ImageViewTarget的onLoadFailed方法
public abstract class ImageViewTarget<Z> extends ViewTarget<ImageView, Z>implements Transition.ViewAdapter { //省略部分代码 ....... public void setDrawable(Drawable drawable) { view.setImageDrawable(drawable); } @Override public void onLoadStarted(@Nullable Drawable placeholder) { super.onLoadStarted(placeholder); setResourceInternal(null); setDrawable(placeholder); } @Override public void onLoadFailed(@Nullable Drawable errorDrawable) { super.onLoadFailed(errorDrawable); setResourceInternal(null); setDrawable(errorDrawable); } //省略部分代码 ....... }
通过以上源码,我想你应该已经明白了后备回调符、错误占位符加载,这里还有一个疑问,加载占位符呢?我们回到之前SingleRequest对象的begin方法,相信你会马上看到在加载状态为RUNNING的时候调用了target.onLoadStarted,也实现了加载中的占位符,到这里我们已经分析完了后备回调符、加载占位符和错误占位符加载底层实现逻辑。
加载图片网络请求
前面分析完各种占位符实现,我们再次回到SingleRequest对象的begin方法,我们可以注意到onSizeReady()和target.getSize()这两句就是加载图片的入口,如果我们在使用glide的时候设置图片加载的大小尺寸,则会调用target.getSize()
/** ViewTarget 类的etSize方法*/ void getSize(@NonNull SizeReadyCallback cb) { int currentWidth = getTargetWidth(); int currentHeight = getTargetHeight(); if (isViewStateAndSizeValid(currentWidth, currentHeight)) { cb.onSizeReady(currentWidth, currentHeight); return; } //省略部分代码 ...... }
通过以上源码,target.getSize()会根据ImageView的宽高来得出图片的加载宽高,最终target.getSize()还是会调用onSizeReady()方法,所以我们就直接来看看SingleRequest对象onSizeReady()方法中做了什么操作。
/** SingleRequest 类的onSizeReady方法*/@Override public 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)); } 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)); } }
在onSizeReady方法中,主要调用了engine.load()方法并返回加载状态,engine.load方法继续接收我们之前传入的各种参数,其中也有我们model对象,也就是之前load方法传入的图片地址。首先我们需要了解engine是什么,顾名思义,engine的英文意思是发动机,而在Glide框架中他就是负责启动图片加载的发动机,主要负责启动加载,我们在前面with方法获取glide对象中得到了engine对象(这里就不贴源码了),我们接着看engine.load()方法进行什么操作
/** 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) { Util.assertMainThread(); long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0; 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 (VERBOSE_IS_LOGGABLE) { 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 (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<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 (VERBOSE_IS_LOGGABLE) { logWithTimeAndKey("Started new load", startTime, key); } return new LoadStatus(cb, engineJob); }/** DecodeJob 类的继承关系*/ class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback, Runnable, Comparable<DecodeJob<?>>, Poolable
通过以上源码,Engine对象的load方前面一段代码都是在处理缓存问题,这里先不进行展开,继续走我们加载图片的主线,往下看我们看到构建了一个EngineJob对象,还构建了一个DecodeJob对象,构建DecodeJob对象又继续接收我们之前传入的各种参数,由DecodeJob对象的继承关系我们可以知道它是Runnable对象,接着我们看到engineJob的start()方法,它直接传入了DecodeJob对象
/** EngineJob 类的start方法*/public void start(DecodeJob<R> decodeJob) { this.decodeJob = decodeJob; GlideExecutor executor = decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor(); executor.execute(decodeJob); }/** GlideExecutor 类的newSourceExecutor方法*/ public static GlideExecutor newSourceExecutor( int threadCount, String name, UncaughtThrowableStrategy uncaughtThrowableStrategy) { return new GlideExecutor( new ThreadPoolExecutor( threadCount /* corePoolSize */, threadCount /* maximumPoolSize */, 0 /* keepAliveTime */, TimeUnit.MILLISECONDS, new PriorityBlockingQueue<Runnable>(), new DefaultThreadFactory(name, uncaughtThrowableStrategy, false))); }
通过以上源码,EngineJob对象的start方法首先还是判断缓存,最终获取的GlideExecutor就是一个线程池执行器(Executor),GlideExecutor中有各种方法获得缓存线程池,还有资源线程池(SourceExecutor),以上源码贴出资源线程池。实际上EngineJob对象的start方法就是用来在线程池中启动DecodeJob这个Runnable对象,也就是说EngineJob的主要作用是开启线程来加载图片,接着我们来看看DecodeJob对象的run方法。
/** DecodeJob 类的run方法*/public void run() { DataFetcher<?> localFetcher = currentFetcher; try { if (isCancelled) { notifyFailed(); return; } runWrapped(); } catch (Throwable t) { //省略部分代码 ....... } finally { if (localFetcher != null) { localFetcher.cleanup(); } GlideTrace.endSection(); } }/** DecodeJob 类的runWrapped方法*/ private void runWrapped() { switch (runReason) { case INITIALIZE: stage = getNextStage(Stage.INITIALIZE); currentGenerator = getNextGenerator(); runGenerators(); break; case SWITCH_TO_SOURCE_SERVICE: runGenerators(); break; case DECODE_DATA: decodeFromRetrievedData(); break; default: throw new IllegalStateException("Unrecognized run reason: " + runReason); } }/** DecodeJob 类的getNextStage方法*/ private Stage getNextStage(Stage current) { switch (current) { case INITIALIZE: return diskCacheStrategy.decodeCachedResource() ? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE); case RESOURCE_CACHE: return diskCacheStrategy.decodeCachedData() ? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE); case DATA_CACHE: // Skip loading from source if the user opted to only retrieve the resource from cache. return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE; case SOURCE: case FINISHED: return Stage.FINISHED; default: throw new IllegalArgumentException("Unrecognized stage: " + current); } } /** DecodeJob 类的getNextGenerator方法*/ 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); } /** DecodeJob 类的runGenerators方法*/ private void runGenerators() { currentThread = Thread.currentThread(); startFetchTime = LogTime.getLogTime(); boolean isStarted = false; while (!isCancelled && currentGenerator != null && !(isStarted = currentGenerator.startNext())) { stage = getNextStage(stage); currentGenerator = getNextGenerator(); if (stage == Stage.SOURCE) { reschedule(); return; } } //省略部分代码 ....... }
上面我们再次贴出了一堆代码,我们来好好梳理一下逻辑,DecodeJob对象的run方法中逻辑很简单,就是调用了自身的runWrapped方法,runWrapped方法中首先判断Stage枚举,前面在创建DecodeJob对象时候设置初始状态为Stage.INITIALIZE,然后接着调用getNextStage方法,这里我们还是继续跳过缓存,所以getNextStage方法最终返回的是Stage.SOURCE状态,接着在getNextGenerator()方法中我们获取就是SourceGenerator对象,也就是run方法中的第一句话DataFetcher<?> localFetcher = currentFetcher中localFetcher就是我们刚刚获得的SourceGenerator对象,接着继续执行runGenerators()方法,在该方法的while循环判断条件执行了currentGenerator.startNext()方法,也就是SourceGenerator对象的startNext()方法
/** SourceGenerator 类的startNext()方法*/ @Override public boolean startNext() { //省略部分代码,跳过缓存部分判断 ........ 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; }/** 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); 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) { modelCache.put(model, 0, 0, model); url = model; } } int timeout = options.get(TIMEOUT); return new LoadData<>(url, new HttpUrlFetcher(url, timeout)); }
通过上面源码,我们接着看到loadData=helper.getLoadData().get(loadDataListIndex++)这一句代码,helper就是DecodeHelper对象,在我们前面创建DecodeJob对象的时候已经把它创建,之前我们在load步骤中传入的model是图片url地址,所以经过DecodeHelper 类的getLoadData() 方法(更细的代码这里就不进行展开了),最终获取的ModelLoader<Object, ?> modelLoader对象则为HttpGlideUrlLoader对象,也就是laodData对象,所以modelLoader.buildLoadData创建则在HttpGlideUrlLoader对象的buildLoadData中实现,上方贴出的该方法源码中把我们model赋值给GlideUrl对象,也就是将其作为URL地址来进行处理,则经过modelLoader.buildLoadData获取的loadData.fetcher则对应HttpUrlFetcher对象,所以loadData.fetcher.loadData调用的就是HttpUrlFetcher对象loadData方法,
/**HttpUrlFetcher类的loadData方法 **/@Override public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) { long startTime = LogTime.getLogTime(); try { 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); } callback.onLoadFailed(e); } finally { if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "Finished http url fetcher fetch in " + LogTime.getElapsedMillis(startTime)); } } }/**HttpUrlFetcher类的loadDataWithRedirects方法 **/ 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); } }
通过以上源码,HttpUrlFetcher对象的loadData方法首先调用自身loadDataWithRedirects方法,接着我们看到该方法源码,这里使用了HttpURLConnection来执行了网络请求,看到这里内心还是有点开心的,前面看了这么多源码,终于看到Glide的网络请求了,开心之后还没完呢,还得接着往下看,执行完网络请求成功,loadDataWithRedirects方法中网络请求成功调用getStreamForSuccessfulRequest返回了一个InputStream流(记住这个InputStream,很关键),然后执行了一个callback回调,而这个回调对象就是我们之前在SourceGenerator对象中调用loadData方法传入SourceGenerator对象本身,所以callback.onDataReady()调用的就是SourceGenerator对象的onDataReady方法
/**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); } }
通过以上源码,不走缓存的情况下则调用cb.onDataFetcherReady,这个cb也就是前面我们new SourceGenerator对象传入的 DecodeJob对象,也就是调用DecodeJob对象onDataFetcherReady方法
/**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 { GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData"); try { decodeFromRetrievedData(); } finally { GlideTrace.endSection(); } } }
通过以上源码,onDataFetcherReady方法中将之前网络请求得到的流赋值给当前的DecodeJob对象的currentData,其他数据都赋值给对应字段,最终调用的是decodeFromRetrievedData方法
加载图片(解码,转码)
/**DecodeJob类的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) { notifyEncodeAndRelease(resource, currentDataSource); } else { runGenerators(); } }/**DecodeJob类的decodeFromData方法 **/ 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(); } }/**DecodeJob类的decodeFromFetcher方法 **/ private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource) throws GlideException { LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass()); return runLoadPath(data, dataSource, path); }
通过以上源码,decodeFromRetrievedData方法调用了decodeFromFetcher方法,在该方法中首先通过decodeHelper.getLoadPath获取LoadPath对象,LoadPath对象其实是根据我们传入的处理数据来返回特定的数据解码转码处理器,我们跟进decodeHelper.getLoadPath看看
/** DecodeHelper类的getLoadPath方法*/<Data> LoadPath<Data, ?, Transcode> getLoadPath(Class<Data> dataClass) { return glideContext.getRegistry().getLoadPath(dataClass, resourceClass, transcodeClass); }/** Registry类的getLoadPath方法*/ @Nullable public <Data, TResource, Transcode> LoadPath<Data, TResource, Transcode> getLoadPath( @NonNull Class<Data> dataClass, @NonNull Class<TResource> resourceClass, @NonNull Class<Transcode> transcodeClass) { //省略部分代码 ....... List<DecodePath<Data, TResource, Transcode>> decodePaths = getDecodePaths(dataClass, resourceClass, transcodeClass); if (decodePaths.isEmpty()) { result = null; } else { result = new LoadPath<>( dataClass, resourceClass, transcodeClass, decodePaths, throwableListPool); } loadPathCache.put(dataClass, resourceClass, transcodeClass, result); } return result; } /** Registry类的getDecodePaths方法*/ @NonNull private <Data, TResource, Transcode> List<DecodePath<Data, TResource, Transcode>> getDecodePaths( @NonNull Class<Data> dataClass, @NonNull Class<TResource> resourceClass, @NonNull Class<Transcode> transcodeClass) { //省略部分代码,去除干扰 List<ResourceDecoder<Data, TResource>> decoders = decoderRegistry.getDecoders(dataClass, registeredResourceClass); ResourceTranscoder<TResource, Transcode> transcoder = transcoderRegistry.get(registeredResourceClass, registeredTranscodeClass); @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") DecodePath<Data, TResource, Transcode> path = new DecodePath<>(dataClass, registeredResourceClass, registeredTranscodeClass, decoders, transcoder, throwableListPool); decodePaths.add(path); } return decodePaths; } /** Registry类的getDecoders方法*/ public synchronized <T, R> List<ResourceDecoder<T, R>> getDecoders(@NonNull Class<T> dataClass, @NonNull Class<R> resourceClass) { List<ResourceDecoder<T, R>> result = new ArrayList<>(); for (String bucket : bucketPriorityList) { List<Entry<?, ?>> entries = decoders.get(bucket); if (entries == null) { continue; } for (Entry<?, ?> entry : entries) { if (entry.handles(dataClass, resourceClass)) { result.add((ResourceDecoder<T, R>) entry.decoder); } } } // TODO: cache result list. return result; }
通过以上源码,我们接着前面跟进DecodeHelper.getLoadPath方法,它调用了Registry对象的getLoadPath方法,Registry对象的getLoadPath方法又调用了自身的getDecodePaths方法,现在我前面提到过得我们网络请求获取的是InputStream流,所以上面源码getDecodePaths方法中Data泛型就是InputStream,在根据getDecoders方法遍历得到解码器ResourceDecoder能处理InputStream流的有StreamBitmapDecoder和StreamGifDecoder,StreamGifDecoder处理的是Gif,我们这里处理图片就之能是StreamBitmapDecoder,它将InputStream流解码成bitmap,然后能将bitmap转换成Drawable的转码器ResourceTranscoder对象则是BitmapDrawableTranscoder,最后getDecodePaths将我们刚刚分析得到的解码器和转码器传递给了新建的DecodePath对象,DecodePath对象就是用来帮助我们进行解码和转码的。
接着我们继续上一步的decodeFromFetcher方法,该方法返回的runLoadPath最终调用了上面获得的DecodePath对象的decode方法
/**DecodePath类的decode方法**/public Resource<Transcode> decode(DataRewinder<DataType> rewinder, int width, int height, @NonNull Options options, DecodeCallback<ResourceType> callback) throws GlideException { Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options); Resource<ResourceType> transformed = callback.onResourceDecoded(decoded); return transcoder.transcode(transformed, options); }/**DecodePath类的decodeResource方法**/@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); } }/**DecodePath类的decodeResourceWithList方法**/ @NonNull private Resource<ResourceType> decodeResourceWithList(DataRewinder<DataType> rewinder, int width, int height, @NonNull Options options, List<Throwable> exceptions) throws GlideException { Resource<ResourceType> result = null; //省略部分代码 ........ ResourceDecoder<DataType, ResourceType> decoder = decoders.get(i); try { DataType data = rewinder.rewindAndGet(); if (decoder.handles(data, options)) { data = rewinder.rewindAndGet(); result = decoder.decode(data, width, height, options); } //省略部分代码 ........ return result; }
通过以上源码,DecodePath对象的decode方法调用了decodeResource方法,decodeResource又调用了decodeResourceWithList方法,经过前面分析,decodeResourceWithList方法中获得的decoder就是前面提到的解码器StreamBitmapDecoder对象,所以我们接着看StreamBitmapDecoder的decode方法
/**StreamBitmapDecoder类的decode方法**/@Override public Resource<Bitmap> decode(@NonNull InputStream source, int width, int height, @NonNull Options options) throws IOException { // Use to fix the mark limit to avoid allocating buffers that fit entire images. final RecyclableBufferedInputStream bufferedStream; final boolean ownsBufferedStream; if (source instanceof RecyclableBufferedInputStream) { bufferedStream = (RecyclableBufferedInputStream) source; ownsBufferedStream = false; } else { bufferedStream = new RecyclableBufferedInputStream(source, byteArrayPool); ownsBufferedStream = true; } ExceptionCatchingInputStream exceptionStream = ExceptionCatchingInputStream.obtain(bufferedStream); MarkEnforcingInputStream invalidatingStream = new MarkEnforcingInputStream(exceptionStream); UntrustedCallbacks callbacks = new UntrustedCallbacks(bufferedStream, exceptionStream); try { return downsampler.decode(invalidatingStream, width, height, options, callbacks); } finally { exceptionStream.release(); if (ownsBufferedStream) { bufferedStream.release(); } } }
通过以上源码,StreamBitmapDecoder的decode方法中只是对InputStream进行包装(装饰模式),可以让Glide进行更多操作,最终调用了downsampler.decode,这个downsampler对象则是Downsampler对象(英文注释:Downsamples, decodes, and rotates images according to their exif orientation.),英文注释大致意思是对图像exif格式进行采样、解码和旋转。而我们这里调用了它的decode方法,也就是对我们前面包装的流进行解码
/**Downsampler类的decode方法**/public Resource<Bitmap> decode(InputStream is, int requestedWidth, int requestedHeight, Options options, DecodeCallbacks callbacks) throws IOException { //省略部分代码 try { Bitmap result = decodeFromWrappedStreams(is, bitmapFactoryOptions, downsampleStrategy, decodeFormat, isHardwareConfigAllowed, requestedWidth, requestedHeight, fixBitmapToRequestedDimensions, callbacks); return BitmapResource.obtain(result, bitmapPool); } finally { releaseOptions(bitmapFactoryOptions); byteArrayPool.put(bytesForOptions); } }/**Downsampler类的decodeFromWrappedStreams方法**/ 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); //省略部分代码 ......... Bitmap rotated = null; if (downsampled != null) { //缩放效正处理 downsampled.setDensity(displayMetrics.densityDpi); rotated = TransformationUtils.rotateImageExif(bitmapPool, downsampled, orientation); if (!downsampled.equals(rotated)) { bitmapPool.put(downsampled); } } return rotated; }/**Downsampler类的decodeStream方法**/ private static Bitmap decodeStream(InputStream is, BitmapFactory.Options options, DecodeCallbacks callbacks, BitmapPool bitmapPool) throws IOException { if (options.inJustDecodeBounds) { is.mark(MARK_POSITION); } else { callbacks.onObtainBounds(); } int sourceWidth = options.outWidth; int sourceHeight = options.outHeight; String outMimeType = options.outMimeType; final Bitmap result; TransformationUtils.getBitmapDrawableLock().lock(); try { result = BitmapFactory.decodeStream(is, null, options); } catch (IllegalArgumentException e) { //省略部分代码 ......... return result; }
作者:maoqitian
链接:https://www.jianshu.com/p/c193f1e78d59
共同学习,写下你的评论
评论加载中...
作者其他优质文章