Glide是一款由Bump Technologies开发的图片加载框架,使得我们可以在Android平台上以极度简单的方式来加载和展示图片。  使用Glide来加载网络图片非常简单,通过Glide.with(this).load(url).into(imageView)这样的一句代码就可以搞定,虽然很简单,但还是需要知其所以然。下面就来梳理一下Glide是如何加载网络图片(不涉及生命周期、缓存等功能点,仅加载网络图片的实现)。

Glide.with(context)

 由于本文不涉及Glide的生命周期,所以直接来看Glide构造方法。

  Glide(@NonNull Context context,@NonNull Engine engine,@NonNull MemoryCache memoryCache,@NonNull BitmapPool bitmapPool,@NonNull ArrayPool arrayPool,@NonNull RequestManagerRetriever requestManagerRetriever,@NonNull ConnectivityMonitorFactory connectivityMonitorFactory,int logLevel,@NonNull RequestOptions defaultRequestOptions,@NonNull Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions) {this.engine = engine;this.bitmapPool = bitmapPool;this.arrayPool = arrayPool;this.memoryCache = memoryCache;this.requestManagerRetriever = requestManagerRetriever;this.connectivityMonitorFactory = connectivityMonitorFactory;DecodeFormat decodeFormat = defaultRequestOptions.getOptions().get(Downsampler.DECODE_FORMAT);bitmapPreFiller = new BitmapPreFiller(memoryCache, bitmapPool, decodeFormat);final Resources resources = context.getResources();//管理组件注册以扩展或替换Glide的默认加载,解码和编码逻辑。registry = new Registry();// Right now we're only using this parser for HEIF images, which are only supported on OMR1+.// If we need this for other file types, we should consider removing this restriction.// Note that order here matters. We want to check the ExifInterface parser first for orientation// and then fall back to DefaultImageHeaderParser for other fields.if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {registry.register(new ExifInterfaceImageHeaderParser());}registry.register(new DefaultImageHeaderParser());Downsampler downsampler = new Downsampler(registry.getImageHeaderParsers(),resources.getDisplayMetrics(), bitmapPool, arrayPool);ByteBufferGifDecoder byteBufferGifDecoder =new ByteBufferGifDecoder(context, registry.getImageHeaderParsers(), bitmapPool, arrayPool);ResourceDecoder<ParcelFileDescriptor, Bitmap> parcelFileDescriptorVideoDecoder =VideoDecoder.parcel(bitmapPool);ByteBufferBitmapDecoder byteBufferBitmapDecoder = new ByteBufferBitmapDecoder(downsampler);StreamBitmapDecoder streamBitmapDecoder = new StreamBitmapDecoder(downsampler, arrayPool);ResourceDrawableDecoder resourceDrawableDecoder =new ResourceDrawableDecoder(context);ResourceLoader.StreamFactory resourceLoaderStreamFactory =new ResourceLoader.StreamFactory(resources);ResourceLoader.UriFactory resourceLoaderUriFactory =new ResourceLoader.UriFactory(resources);ResourceLoader.FileDescriptorFactory resourceLoaderFileDescriptorFactory =new ResourceLoader.FileDescriptorFactory(resources);ResourceLoader.AssetFileDescriptorFactory resourceLoaderAssetFileDescriptorFactory =new ResourceLoader.AssetFileDescriptorFactory(resources);BitmapEncoder bitmapEncoder = new BitmapEncoder(arrayPool);BitmapBytesTranscoder bitmapBytesTranscoder = new BitmapBytesTranscoder();GifDrawableBytesTranscoder gifDrawableBytesTranscoder = new GifDrawableBytesTranscoder();ContentResolver contentResolver = context.getContentResolver();registry.append(ByteBuffer.class, new ByteBufferEncoder())//编码器,当缓存数据到本地时会用到.append(InputStream.class, new StreamEncoder(arrayPool))/* Bitmaps */.append(Registry.BUCKET_BITMAP, ByteBuffer.class, Bitmap.class, byteBufferBitmapDecoder).append(Registry.BUCKET_BITMAP, InputStream.class, Bitmap.class, streamBitmapDecoder).append(Registry.BUCKET_BITMAP,ParcelFileDescriptor.class,Bitmap.class,parcelFileDescriptorVideoDecoder).append(Registry.BUCKET_BITMAP,AssetFileDescriptor.class,Bitmap.class,VideoDecoder.asset(bitmapPool)).append(Bitmap.class, Bitmap.class, UnitModelLoader.Factory.<Bitmap>getInstance()).append(Registry.BUCKET_BITMAP, Bitmap.class, Bitmap.class, new UnitBitmapDecoder()).append(Bitmap.class, bitmapEncoder)/* BitmapDrawables */.append(Registry.BUCKET_BITMAP_DRAWABLE,ByteBuffer.class,BitmapDrawable.class,new BitmapDrawableDecoder<>(resources, byteBufferBitmapDecoder)).append(Registry.BUCKET_BITMAP_DRAWABLE,InputStream.class,BitmapDrawable.class,new BitmapDrawableDecoder<>(resources, streamBitmapDecoder)).append(Registry.BUCKET_BITMAP_DRAWABLE,ParcelFileDescriptor.class,BitmapDrawable.class,new BitmapDrawableDecoder<>(resources, parcelFileDescriptorVideoDecoder)).append(BitmapDrawable.class, new BitmapDrawableEncoder(bitmapPool, bitmapEncoder))/* GIFs */.append(Registry.BUCKET_GIF,InputStream.class,GifDrawable.class,new StreamGifDecoder(registry.getImageHeaderParsers(), byteBufferGifDecoder, arrayPool)).append(Registry.BUCKET_GIF, ByteBuffer.class, GifDrawable.class, byteBufferGifDecoder).append(GifDrawable.class, new GifDrawableEncoder())/* GIF Frames */// Compilation with Gradle requires the type to be specified for UnitModelLoader here..append(GifDecoder.class, GifDecoder.class, UnitModelLoader.Factory.<GifDecoder>getInstance()).append(Registry.BUCKET_BITMAP,GifDecoder.class,Bitmap.class,new GifFrameResourceDecoder(bitmapPool))/* Drawables */.append(Uri.class, Drawable.class, resourceDrawableDecoder).append(Uri.class, Bitmap.class, new ResourceBitmapDecoder(resourceDrawableDecoder, bitmapPool))/* Files */.register(new ByteBufferRewinder.Factory()).append(File.class, ByteBuffer.class, new ByteBufferFileLoader.Factory()).append(File.class, InputStream.class, new FileLoader.StreamFactory()).append(File.class, File.class, new FileDecoder()).append(File.class, ParcelFileDescriptor.class, new FileLoader.FileDescriptorFactory())// Compilation with Gradle requires the type to be specified for UnitModelLoader here..append(File.class, File.class, UnitModelLoader.Factory.<File>getInstance())/* Models */.register(new InputStreamRewinder.Factory(arrayPool)).append(int.class, InputStream.class, resourceLoaderStreamFactory).append(int.class,ParcelFileDescriptor.class,resourceLoaderFileDescriptorFactory).append(Integer.class, InputStream.class, resourceLoaderStreamFactory).append(Integer.class,ParcelFileDescriptor.class,resourceLoaderFileDescriptorFactory).append(Integer.class, Uri.class, resourceLoaderUriFactory).append(int.class,AssetFileDescriptor.class,resourceLoaderAssetFileDescriptorFactory).append(Integer.class,AssetFileDescriptor.class,resourceLoaderAssetFileDescriptorFactory).append(int.class, Uri.class, resourceLoaderUriFactory).append(String.class, InputStream.class, new DataUrlLoader.StreamFactory<String>()).append(Uri.class, InputStream.class, new DataUrlLoader.StreamFactory<Uri>()).append(String.class, InputStream.class, new StringLoader.StreamFactory()).append(String.class, ParcelFileDescriptor.class, new StringLoader.FileDescriptorFactory()).append(String.class, AssetFileDescriptor.class, new StringLoader.AssetFileDescriptorFactory()).append(Uri.class, InputStream.class, new HttpUriLoader.Factory()).append(Uri.class, InputStream.class, new AssetUriLoader.StreamFactory(context.getAssets())).append(Uri.class,ParcelFileDescriptor.class,new AssetUriLoader.FileDescriptorFactory(context.getAssets())).append(Uri.class, InputStream.class, new MediaStoreImageThumbLoader.Factory(context)).append(Uri.class, InputStream.class, new MediaStoreVideoThumbLoader.Factory(context)).append(Uri.class,InputStream.class,new UriLoader.StreamFactory(contentResolver)).append(Uri.class,ParcelFileDescriptor.class,new UriLoader.FileDescriptorFactory(contentResolver)).append(Uri.class,AssetFileDescriptor.class,new UriLoader.AssetFileDescriptorFactory(contentResolver)).append(Uri.class, InputStream.class, new UrlUriLoader.StreamFactory()).append(URL.class, InputStream.class, new UrlLoader.StreamFactory()).append(Uri.class, File.class, new MediaStoreFileLoader.Factory(context))//进行网络下载.append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory()).append(byte[].class, ByteBuffer.class, new ByteArrayLoader.ByteBufferFactory()).append(byte[].class, InputStream.class, new ByteArrayLoader.StreamFactory()).append(Uri.class, Uri.class, UnitModelLoader.Factory.<Uri>getInstance()).append(Drawable.class, Drawable.class, UnitModelLoader.Factory.<Drawable>getInstance()).append(Drawable.class, Drawable.class, new UnitDrawableDecoder())/* Transcoders */.register(Bitmap.class,BitmapDrawable.class,new BitmapDrawableTranscoder(resources)).register(Bitmap.class, byte[].class, bitmapBytesTranscoder).register(Drawable.class,byte[].class,new DrawableBytesTranscoder(bitmapPool, bitmapBytesTranscoder, gifDrawableBytesTranscoder)).register(GifDrawable.class, byte[].class, gifDrawableBytesTranscoder);...}复制代码

 构造方法最重要的就是Register这个类,它主要是用于管理组件注册以扩展或替换Glide的默认加载,解码和编码逻辑,比如我们可以使用giflib替换Glide自带的GIF解码器,来提高性能,可以使用OKHttp来替换Glide默认的下载实现,也可以自己定义比Glide默认性能更好的编解码器等。构造方法里默认注册了HttpGlideUrlLoader这个类,为什么要说这个类尼,因为默认的下载实现就在这个类。  with是Glide的一组静态方法,它里面有关于Glide生命周期的实现。来看看这组静态方法的实现。

  public static RequestManager with(@NonNull FragmentActivity activity) {return getRetriever(activity).get(activity);}public static RequestManager with(@NonNull Activity activity) {return getRetriever(activity).get(activity);}...
复制代码

 从上面可以看出with都返回了一个RequestManager对象。

load(url)

loadRequestManager里的一组方法,根据传入参数来不同的实现,这里就以传入一个字符串的url为例。

  public RequestBuilder<Drawable> load(@Nullable String string) {return asDrawable().load(string);}//这里代表返回一个Drawable类型的图片public RequestBuilder<Drawable> asDrawable() {return as(Drawable.class);}//创建一个RequestBuilder对象。public <ResourceType> RequestBuilder<ResourceType> as(@NonNull Class<ResourceType> resourceClass) {//resourceClass对应着RequestBuilder的transcodeClass变量return new RequestBuilder<>(glide, this, resourceClass, context);}
复制代码

RequestBuilder对象创建成功后,在调用load方法将图片路径赋值给model这个变量。

into(imageView)

 前面快速介绍了Glide.with(context)load(url)的实现,虽然它们也并不简单,但它们也没有实现图片的下载,那么图片的下载是从哪里开始的尼?就是通过into方法来实现的,来看一下into方法的实现。

  public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {...return into(//transcodeClass就是前面传递过来的Drawable.classglideContext.buildImageViewTarget(view, transcodeClass),/*targetListener=*/ null,requestOptions);}
复制代码

 由于transcodeClass是一个Drawable类型,所以glideContext.buildImageViewTarget(view, transcodeClass)创建了一个DrawableImageViewTarget对象,来看看DrawableImageViewTarget的实现。

public class DrawableImageViewTarget extends ImageViewTarget<Drawable> {public DrawableImageViewTarget(ImageView view) {super(view);}/*** @deprecated Use {@link #waitForLayout()} instead.*/// Public API.@SuppressWarnings({"unused", "deprecation"})@Deprecatedpublic DrawableImageViewTarget(ImageView view, boolean waitForLayout) {super(view, waitForLayout);}//这里是不是很熟悉啊,就是展示图片@Overrideprotected void setResource(@Nullable Drawable resource) {view.setImageDrawable(resource);}
}
复制代码

 再来看into方法的实现。

  private <Y extends Target<TranscodeType>> Y into(//target就是前面创建的DrawableImageViewTarget对象@NonNull Y target,@Nullable RequestListener<TranscodeType> targetListener,@NonNull RequestOptions options) {...//创建一个Request对象,默认是SingleRequest对象Request request = buildRequest(target, targetListener, options);//target就是前面创建的DrawableImageViewTarget对象//拿到target中的Request对象Request previous = target.getRequest();if (request.isEquivalentTo(previous)&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {//释放Request对象,因为target已存在同样的Request对象了request.recycle();if (!Preconditions.checkNotNull(previous).isRunning()) {//如果没有加载就开始加载previous.begin();}return target;}requestManager.clear(target);//设置target的Requesttarget.setRequest(request);//开始下载requestManager.track(target, request);return target;}
复制代码

 默认创建的Request对象是SingleRequest,由于本文分析的是第一次加载图片,所以我们来看RequestManagertrack方法。

  void track(@NonNull Target<?> target, @NonNull Request request) {...requestTracker.runRequest(request);}//RequestTracker中public void runRequest(@NonNull Request request) {requests.add(request);if (!isPaused) {//当没有暂停时Request就开始执行request.begin();} else {//暂停执行request.clear();...pendingRequests.add(request);}}
复制代码

 由于这里Request的具体实现是SingleRequest,所以我们来看它的begin方法。

  @Overridepublic void begin() {...//传入的model为null,在本文中就是传入的URL为nullif (model == null) {if (Util.isValidDimensions(overrideWidth, overrideHeight)) {width = overrideWidth;height = overrideHeight;}...//图片加载失败onLoadFailed(new GlideException("Received null model"), logLevel);return;}//从缓存中拿数据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 {//根据View的宽高来计算出图片的宽高,最后回调的也是onSizeReady方法target.getSize(this);}if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)&& canNotifyStatusChanged()) {//图片开始加载时的默认显示target.onLoadStarted(getPlaceholderDrawable());}...}}public void onSizeReady(int width, int height) {stateVerifier.throwIfRecycled();...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);...}}
复制代码

 如果图片的宽高已经确定就直接调用onSizeReady,否先确定宽高再调用onSizeReady方法,该方法中最关键的是调用Engineload方法,来看一下实现。

  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) {...//根据model计算出每张图片对应的keyEngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,resourceClass, transcodeClass, options);//从ActiveResources中获取图片,ActiveResources是一个弱引用的HashMapEngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);if (active != null) {cb.onResourceReady(active, DataSource.MEMORY_CACHE);return null;}//从缓存中获取图片,采用了LrucacheEngineResource<?> cached = loadFromCache(key, isMemoryCacheable);if (cached != null) {cb.onResourceReady(cached, DataSource.MEMORY_CACHE);return null;}EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);if (current != null) {current.addCallback(cb);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);return new LoadStatus(cb, engineJob);}
复制代码

 Glide会首先从缓存中获取数据,如果没有的话再从网络获取。EngineJobDecodeJob两个类非常重要,EngineJob主要进行线程之间的切换,DecodeJob主要是从本地或者网络获取数据的实现,来看EngineJobstart的实现。

  public void start(DecodeJob<R> decodeJob) {this.decodeJob = decodeJob;GlideExecutor executor = decodeJob.willDecodeFromCache()? diskCacheExecutor: getActiveSourceExecutor();//向子线程添加任务executor.execute(decodeJob);}
复制代码

 在这里就切换到下载图片线程,由于DecodeJob实现了Runnable接口,所以就来看run的方法。

 public void run() {...try {if (isCancelled) {notifyFailed();return;}runWrapped();} catch (Throwable t) {...} finally {...}}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);}}
复制代码

 很明显这里的重点是runGenerators,来看看runGenerators的实现。

  private void runGenerators() {...boolean isStarted = false;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();}}
复制代码

 由于这里不涉及到缓存,所以调用SourceGeneratorstartNext的方法,当网络返回数据时则dataToCache不为null,就会存储数据到本地。否则就从网络获取数据。

  public boolean startNext() {//当下载成功后,dataToCache 则不为null,需要写入缓存,后面会用到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的实现是MultiModelLoader,loadData.fetcher的实现是MultiFetcherloadData.fetcher.loadData(helper.getPriority(), this);}}return started;}
复制代码

 这里的loadData的实现是MultiModelLoaderfetcher的实现是MultiFetcher,然后调用loadData方法来加载数据。

    @Overridepublic void loadData(@NonNull Priority priority, @NonNull DataCallback<? super Data> callback) {...//这里的Fetcher是可以定制的,默认实现是HttpUrlFetcherfetchers.get(currentIndex).loadData(priority, this);}
复制代码

 由于我们没有任何定制fetcher,所以调用的是HttpUrlFetcherload方法。

  @Overridepublic 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) {...callback.onLoadFailed(e);} finally {...}}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);}}复制代码

 到这里想必大家就很熟悉了,就是连接网络并下载图片。将数据通过callback.onDataReady(result);返回,这个callback其实就是MultiFetcher

    public void onDataReady(@Nullable Data data) {if (data != null) {callback.onDataReady(data);} else {startNextOrFail();}}
复制代码

 这个callback其实就是SourceGenerator

  public void onDataReady(Object data) {DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {dataToCache = data;...cb.reschedule();} else {...}}
复制代码

 这个cb其实就是DecodeJob

  public void reschedule() {//切换runReason的值runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;callback.reschedule(this);}
复制代码

 这个callback就是EngineJob,再来看它的reschedule方法。

  @Overridepublic void reschedule(DecodeJob<?> job) {//将任务提交给线程池getActiveSourceExecutor().execute(job);}
复制代码

 这里是切换到缓存数据线程,那么就会执行DecodeJobrun方法,前面介绍过,在该方法内执行的是runWrapped方法,由于前面将runReason的值修改为SWITCH_TO_SOURCE_SERVICE,所以就会直接执行runGenerators然后再次调用SourceGeneratorstartNext方法,前面在介绍该方法时,说过如果有数据就写入缓存,这时候就会将数据写入缓存并调用DataCacheGeneratorstartNext方法。

  @Overridepublic boolean startNext() {...loadData = null;boolean started = false;while (!started && hasNextModelLoader()) {ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);loadData =modelLoader.buildLoadData(cacheFile, helper.getWidth(), helper.getHeight(),helper.getOptions());if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {started = true;//加载从缓存中获取数据//loadData的实现类是ByteBufferFileLoader//loadData.fetcher的实现类是ByteBufferFetcherloadData.fetcher.loadData(helper.getPriority(), this);}}return started;}
复制代码

 这里就调用了ByteBufferFetcherloadData方法。

    @Overridepublic void loadData(@NonNull Priority priority,@NonNull DataCallback<? super ByteBuffer> callback) {ByteBuffer result;try {//从缓存从获取数据result = ByteBufferUtil.fromFile(file);} catch (IOException e) {...//数据获取失败callback.onLoadFailed(e);return;}//数据获取成功callback.onDataReady(result);}
复制代码

 这里的callback就是DataCacheGenerator

  @Overridepublic void onDataReady(Object data) {cb.onDataFetcherReady(sourceKey, data, loadData.fetcher, DataSource.DATA_DISK_CACHE, sourceKey);}
复制代码

 这里的cb就是SourceGenerator

  @Overridepublic void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,DataSource dataSource, Key attemptedKey) {...cb.onDataFetcherReady(sourceKey, data, fetcher, loadData.fetcher.getDataSource(), sourceKey);}
复制代码

 前面说过SourceGenerator中的cb就是DecodeJob

  @Overridepublic void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,DataSource dataSource, Key attemptedKey) {...if (Thread.currentThread() != currentThread) {runReason = RunReason.DECODE_DATA;callback.reschedule(this);} else {...try {decodeFromRetrievedData();} finally {...}}}private void decodeFromRetrievedData() {...Resource<R> resource = null;try {resource = decodeFromData(currentFetcher, currentData, currentDataSource);} catch (GlideException e) {...}if (resource != null) {notifyEncodeAndRelease(resource, currentDataSource);} else {runGenerators();}}private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {...//该将图片显示在ImageView上了notifyComplete(result, dataSource);...}private void notifyComplete(Resource<R> resource, DataSource dataSource) {setNotifiedOrThrow();callback.onResourceReady(resource, dataSource);}
复制代码

 前面说过这个callback就是EngineJob

  @Overridepublic void onResourceReady(Resource<R> resource, DataSource dataSource) {...//切换回主线程MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();}void handleResultOnMainThread() {...//noinspection ForLoopReplaceableByForEach to improve perffor (int i = 0, size = cbs.size(); i < size; i++) {ResourceCallback cb = cbs.get(i);if (!isInIgnoredCallbacks(cb)) {engineResource.acquire();cb.onResourceReady(engineResource, dataSource);}}...release(false /*isRemovedFromQueue*/);}
复制代码

 在EngineJobonResourceReady中切换回主线程。并将数据传给cb的onResourceReady方法,这里的cb是SingleRequest

  public void onResourceReady(Resource<?> resource, DataSource dataSource) {...onResourceReady((Resource<R>) resource, (R) received, dataSource);}private void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {...try {...if (!anyListenerHandledUpdatingTarget) {Transition<? super R> animation =animationFactory.build(dataSource, isFirstResource);//展示图片target.onResourceReady(result, animation);}} finally {isCallingCallbacks = false;}notifyLoadSuccess();}
复制代码

 在前面说过,target的实现类是DrawableImageViewTarget。但在该类中并没有onResourceReady这个方法,于是去父类查找。

  @Overridepublic 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) {//setResource是个抽象方法setResource(resource);maybeUpdateAnimatable(resource);}
复制代码

setResource是个抽象方法,在DrawableImageViewTarget中实现。

  @Overrideprotected void setResource(@Nullable Drawable resource) {//view是ImageViewview.setImageDrawable(resource);}
复制代码

 这里相必大家都很熟悉了吧。  到此Glide加载网络图片的流程就完结了,太复杂了,特别是into方法,由于很复杂,所以画了张时序图,如下:

 建议结合源码一起阅读。

转载于:https://juejin.im/post/5c789e0ae51d451ecc2028ed

Glide源码(基于4.8版本)解析相关推荐

  1. Glide源码解析-加载流程

    1 引言 一直想要阅读Glide源码,但是苦于时间和功力都不够,总是断断续续的,趁着现在有一些空暇时间,来简要分析Glide的源码.Glide的实现太过复杂,不可能做到面面俱到,如果每一行都细致分析, ...

  2. Glide 源码解析之监听生命周期

    code小生 一个专注大前端领域的技术平台公众号回复Android加入安卓技术群 作者:断了谁的弦 链接:https://www.jianshu.com/p/1169a91342a9 声明:本文已获断 ...

  3. 深入剖析Glide源码-4.15版本(一)

    文章目录 深入剖析Glide源码-4.15版本(一) 一行代码进行图片加载 一.生命周期管理 Glide初始化 RequestManager构建 1. 传入activity时 RequestManag ...

  4. Glide源码解析之山清水秀疑无路(一)

    本篇主要由以下内容构成: 1.框架结构简介 2.按照glide源码使用的时序图进行深入简述的方式讲解 3.核心类和核心模块总结 ps:本人博客写的太少,逻辑有时会走火入魔,希望你看到我的文章,可以理清 ...

  5. 【栖梧-源码-spring】@Bean从解析到注册到beanDefinitionMap

    [栖梧-源码-spring]@Bean从解析到注册到beanDefinitionMap 序幕 源码阅读技巧 本文说明 类 ConfigurationClassParser#doProcessConfi ...

  6. 2022去/水印小程序源码+基于WordPress插件

    正文: 2022去/水印小程序源码+基于WordPress插件,本版本代码是全开源的,基于Wordpress的插件开发的. 上传到Wordpress,安装插件,启动之后,绑定自己的小程序id即可,wo ...

  7. 详谈高大上的图片加载框架Glide -源码篇

    在上篇文章中,我们介绍了Glide图片加载框架的使用,通过之前的学习,我们可能已经能熟练的将Glide图片加载框架运用到我们的项目中,但是如果有人问你它是如何加载,工作原理是怎样的?为什么自定义Gli ...

  8. javaweb毕业设计源码 基于ssm农产品供销服务系统

    一.源码描述   这是一款基于web的前后端分离JAVA+SSM源码 基于B/S开发,包含毕业论文和答辩ppt,开发工具idea支持eclipse,MySQL,适合作为毕业设计使用,感兴趣的朋友可以下 ...

  9. PHP单页面加密视频教程附源码,thinkphp3.2最新版本项目实战视频教程(含源码)

    php教程 当前位置:主页 > php教程 > thinkphp3.2最新版本项目实战视频教程(含源码) thinkphp3.2最新版本项目实战视频教程(含源码) 教程大小:2.1GB   ...

  10. Glide源码阅读理解一小时

    前言 这篇图.文.表.代码一起组成的 Glide 源码分析的文章是在上一篇文章 Android-Universal-Image-Loader源码分析 中之后的又一篇图片加载框架源码解析,它也具备了 I ...

最新文章

  1. linux系统主要常见目录结构
  2. 为了在元宇宙里摸到东西,扎克伯格整出了一款新电子皮肤,成本6美元
  3. 人工智能:第四章 计算智能(1)
  4. Androd开发之通过ComponentName和setComponent以及scheme打开外部应用 | 打开任意页面 | 打开指定页面
  5. c语言文件指针ab命令,C语言试题,~库(完整版~).doc
  6. Jupyter notebook 导入和卸载 conda 虚拟环境
  7. php页面的特点_带你一分钟了解php的四大特性八大优势(详情)
  8. linux系统怎么刷新,Fedora Linux如何更新系统
  9. 【黑苹果 Hackintosh】Delll成就5468(Vostro 5468)黑苹果
  10. 富士通服务器操作系统安装,U盘为富士通LIFEBOOK SH760笔记本安装原版win7系统教程...
  11. 神经网络模型如何使用的,神经网络模型是干嘛的
  12. 马成荣版计算机应用基础 教案,课改理念在中职《计算机应用基础》教学中的应用...
  13. matlab中matconvnet,MATLAB2017a编译MatConvNet过程中出现的各种问题
  14. OBS视频采集流程分析
  15. 微信自动回复和群聊消息完善
  16. 自动弹出的html,360浏览器自动弹出网页怎么解决?
  17. Python房贷计算器GUI(等额本息,等额本金)
  18. 免上传音乐外链(QQ音乐)
  19. Git学习-本地版本库的创建与简单操作
  20. vue vue-print-nb 打印图片

热门文章

  1. 第六阶段 小学期(一)——电子商务
  2. python-copy模块使用
  3. 细说Java主流日志工具库
  4. 实验5,利用三层交换机实现VLAN间路由
  5. 让DJANGO里的get_success_url定义的reverse_lazy带参数跳转
  6. spring配置datasource三种方式
  7. PHP截取两个字符串之间的内容
  8. iframe批量异步上传图片
  9. Asp.Net web.config配置节点大全详解
  10. java写文件方法之比较