Glide源码(基于4.8版本)解析

版权声明:未经本人允许,严禁转载 https://blog.csdn.net/lmh_19941113/article/details/86010929

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);

    ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory();
    glideContext =
        new GlideContext(
            context,
            arrayPool,
            registry,
            imageViewTargetFactory,
            defaultRequestOptions,
            defaultTransitionOptions,
            engine,
            logLevel);
  }

 构造方法最重要的就是Register这个类,它主要是用于管理组件注册以扩展或替换Glide的默认加载,解码和编码逻辑,比如我们可以使用giflib替换Glide自带的GIF解码器,来提高性能,也可以使用OKHttp来替换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.class
        glideContext.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"})
  @Deprecated
  public DrawableImageViewTarget(ImageView view, boolean waitForLayout) {
    super(view, waitForLayout);
  }
  //这里是不是很熟悉啊,就是展示图片
  @Override
  protected 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的Request
    target.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方法。

  @Override
  public void begin() {
    ...
    //传入的model为null,在本文中就是传入的URL为null
    if (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中最关键的是调用了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计算出每张图片对应的key
    EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
        resourceClass, transcodeClass, options);
    //从ActiveResources中获取图片
    EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
    if (active != null) {
      cb.onResourceReady(active, DataSource.MEMORY_CACHE);
      return null;
    }
    //从缓存中获取图片
    EngineResource<?> 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);
  }

EngineJobDecodeJob两个类非常重要,其重要性在后面就会慢慢体现出来。来看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的方法,来看此方法的实现,要注意一下该方法里缓存数据到本地的实现,因为后面会用到。

  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的实现是MultiFetcher
        loadData.fetcher.loadData(helper.getPriority(), this);
      }
    }
    return started;
  }

 在方法的最后调用了MultiFetcherloadData方法来加载数据,再来看该方法的实现。

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

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

  @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) {
      ...
      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方法。

  @Override
  public void reschedule(DecodeJob<?> job) {
    //将任务提交给线程池
    getActiveSourceExecutor().execute(job);
  }

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

  @Override
  public 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的实现类是ByteBufferFetcher
        loadData.fetcher.loadData(helper.getPriority(), this);
      }
    }
    return started;
  }

 这里就调用了ByteBufferFetcherloadData方法。

    @Override
    public 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

  @Override
  public void onDataReady(Object data) {
    cb.onDataFetcherReady(sourceKey, data, loadData.fetcher, DataSource.DATA_DISK_CACHE, sourceKey);
  }

 这里的cb就是SourceGenerator

  @Override
  public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
      DataSource dataSource, Key attemptedKey) {
    ...
    cb.onDataFetcherReady(sourceKey, data, fetcher, loadData.fetcher.getDataSource(), sourceKey);
  }

 前面说过SourceGenerator中的cb就是DecodeJob

  @Override
  public 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

  @Override
  public void onResourceReady(Resource<R> resource, DataSource dataSource) {
    ...
    //切换回主线程
    MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
  }
  void handleResultOnMainThread() {
    ...
    //noinspection ForLoopReplaceableByForEach to improve perf
    for (int i = 0, size = cbs.size(); i < size; i++) {
      ResourceCallback cb = cbs.get(i);
      if (!isInIgnoredCallbacks(cb)) {
        engineResource.acquire();
        cb.onResourceReady(engineResource, dataSource);
      }
    }
    ...
    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这个方法,于是去父类查找。

  @Override
  public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
    if (transition == null || !transition.transition(resource, this)) {
      setResourceInternal(resource);
    } else {
      maybeUpdateAnimatable(resource);
    }
  }
  private void setResourceInternal(@Nullable Z resource) {
    //setResource是个抽象方法
    setResource(resource);
    maybeUpdateAnimatable(resource);
  }

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

  @Override
  protected void setResource(@Nullable Drawable resource) {
    //view是ImageView
    view.setImageDrawable(resource);
  }

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

在这里插入图片描述

 建议结合源码一起阅读。

猜你喜欢

转载自blog.csdn.net/lmh_19941113/article/details/86010929