美文网首页
Glide ① — with,load,into

Glide ① — with,load,into

作者: leap_ | 来源:发表于2020-08-18 16:05 被阅读0次

本文将介绍下面三个方法的执行流程

    Glide.with(this).load(url).into(imageView);

With

  public static RequestManager with(@NonNull Context context) {
    return getRetriever(context).get(context);
  }
  public static RequestManager with(@NonNull Activity activity) {
    return getRetriever(activity).get(activity);
  }
  public static RequestManager with(@NonNull FragmentActivity activity) {
    return getRetriever(activity).get(activity);
  }
  public static RequestManager with(@NonNull Fragment fragment) {
    return getRetriever(fragment.getActivity()).get(fragment);
  }
  public static RequestManager with(@NonNull View view) {
    return getRetriever(view.getContext()).get(view);
  }

with()用来接收一个Context对象,可以直接是Context,也可以是Activity,Fragment,View;getRetriever()会获取一个RequestManagerRetriever对象,再通过get()拿到一个RequestManager对象;
至此我们可以知道Context是被封装在RequestManager中的,看一下get对于Context处理的逻辑:

  public RequestManager get(@NonNull Context context) {
    if (context == null) {
      throw new IllegalArgumentException("You cannot start a load on a null Context");
    } else if (Util.isOnMainThread() && !(context instanceof Application)) {
      if (context instanceof FragmentActivity) {
        return get((FragmentActivity) context);
      } else if (context instanceof Activity) {
        return get((Activity) context);
      } else if (context instanceof ContextWrapper) {
        return get(((ContextWrapper) context).getBaseContext());
      }
    }

    return getApplicationManager(context);
  }

在get()中,会根据传入的Context参数的类型分为两种,一种是Application类型,还有一种是非Application类型(Activity,Context);

1. 如果Context是Application类型:
  /**
   * The top application level RequestManager.
   */
  private volatile RequestManager applicationManager;

  private RequestManager getApplicationManager(@NonNull Context context) {
    // Either an application context or we're on a background thread.
    if (applicationManager == null) {
      synchronized (this) {
        if (applicationManager == null) {
          // Normally pause/resume is taken care of by the fragment we add to the fragment or
          // activity. However, in this case since the manager attached to the application will not
          // receive lifecycle events, we must force the manager to start resumed using
          // ApplicationLifecycle.
          Glide glide = Glide.get(context.getApplicationContext());
          applicationManager =
              factory.build(
                  glide,
                  new ApplicationLifecycle(),
                  new EmptyRequestManagerTreeNode(),
                  context.getApplicationContext());
        }
      }
    }
    return applicationManager;
  }

如果我们在with()中传入的是一个Application,或者我们在子线程使用Glide,就会通过ApplicationLifecycle,Application Context去构造一个RequestManager,这中情况下,Glide的生命周期是和App绑定的;

2. 如果是非Application类型的Context
  @NonNull
  public RequestManager get(@NonNull Fragment fragment) {
    if (Util.isOnBackgroundThread()) {
      return get(fragment.getActivity().getApplicationContext());
    } else {
      FragmentManager fm = fragment.getChildFragmentManager();
      return supportFragmentGet(fragment.getActivity(), fm, fragment, fragment.isVisible());
    }
  }

  private RequestManager supportFragmentGet(
      @NonNull Context context,
      @NonNull FragmentManager fm,
      @Nullable Fragment parentHint,
      boolean isParentVisible) {
    SupportRequestManagerFragment current =
        getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
      // TODO(b/27524013): Factor out this Glide.get() call.
      Glide glide = Glide.get(context);
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }

public class SupportRequestManagerFragment extends Fragment {
  private final ActivityFragmentLifecycle lifecycle;
  @Override
  public void onStart() {
    super.onStart();
    lifecycle.onStart();
  }

  @Override
  public void onStop() {
    super.onStop();
    lifecycle.onStop();
  }

  @Override
  public void onDestroy() {
    super.onDestroy();
    lifecycle.onDestroy();
    unregisterFragmentWithRoot();
  }
}

在这种情况下,会通过Activity/Fragment获取一个FragmentManager对象,然后去创建一个空的fragment(SupportRequestManagerFragment ),这个Fragment是不可见的,它的内部会设置一个接口,用于监听这个Fragment的生命周期,在RequestManagerWraper中,将这个不可见的Fragment同我们的界面进行绑定,那么这个不可见的Fragment就和我们的界面生命周期一致了,这样Glide就可以自动感知调用它的Activity/Fragment的生命周期了;

with() 的整体逻辑

load

with()返回的是一个RequestManager对象,所以load是由它调用的;
load也进行了很多重载,(Bitmap,Uri,File,byte[]),这里只分析平时使用的最多的一种情况:

  public RequestBuilder<Drawable> load(@Nullable String string) {
    return asDrawable().load(string);
  }

  @NonNull
  private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
    this.model = model;
    isModelSet = true;
    return this;
  }

这里主要是创建了一个RequestBuilder对象

into

在分析into前,先理清楚几个核心Api的作用:
  • RequestManager:绑定管理生命周期

  • RequestBuilder:构建Request请求,构建Target

  • Target:into方法会返回一个Target,Target是一个Glide可以加载图片资源的具有生命周期的目标,有很多实现类,这里介绍一个常见的的实现类:

  1. BitmapImageViewTarget:glide可以加载一个bitmap资源到imageView上;
  • Request:加载图片的请求,具体有三个实现类:
  1. SingleRequest:负责调用Engine执行请求,将结果展示在Target上
  2. ErrorRequestCoordinator:主要用来处理加载失败error的场景;
  3. ThumbnailRequestCoordinator:用来协调两个请求,因为有的请求需要同时加载原图和缩略图

into:

RequestBuilder
  public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
    Util.assertMainThread();
...
    return into(
        glideContext.buildImageViewTarget(view, transcodeClass),    // 创建ImageViewTarget
        /*targetListener=*/ null,
        requestOptions);
  }

  private <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @Nullable RequestListener<TranscodeType> targetListener,
      @NonNull RequestOptions options) {
    
    //  分析1
    Request request = buildRequest(target, targetListener, options);

    Request previous = target.getRequest();
    if (request.isEquivalentTo(previous)
        && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
      request.recycle();
      if (!Preconditions.checkNotNull(previous).isRunning()) {
        //  分析2 
        previous.begin();
      }
      return target;
    }
  }

在我们调用into(imageView)后,会通过这个imageView创建一个ImageViewTarget对象,然后在构建一个Request对象;

  • 通过ImageViewTarget构建Request对象
  • 调用Request的begin(),让Engine处理Request;
SingleRequest
  public void begin() {
...
    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);
    }
...
  }

  public void onSizeReady(int width, int height) {
...
    loadStatus = engine.load(...);
  }

如果Imageview还没有绘制好,那么我们的Request.begin()是不会去执行的,ImageViewTarget会注册View 的OnPreDrawListener事件,在View准备好后,会调用onSizeReady()

RequestBuilder的into逻辑

剩下的工作都是交给Engine来完成的,Engine的事情比较多,所以Engine的逻辑图另外再画一张

Engine
  public <R> LoadStatus load(...) {
...
    //  创建 EngineJob
    EngineJob<R> engineJob = engineJobFactory.build(...);
     //  创建 DecodeJob
    DecodeJob<R> decodeJob = decodeJobFactory.build(...);
  }
  
    engineJob.addCallback(cb);
    //  启动decodeJob
    engineJob.start(decodeJob);

在Engine的load中创建了EngineJob,DecodeJob;

  • EngineJob:用于开启DecodeJob,管理load过程的回调
    (注释是这么说的: manages a load by adding and removing callbacks )
  • DecodeJob:
  1. 从缓存或数据源中加载原始数据:decoding resources either from cached data or from the original source
  2. 通过解码器转换为相应的资源类型:applying transformations and transcodes
EngineJob
  public void start(DecodeJob<R> decodeJob) {
    this.decodeJob = decodeJob;
    GlideExecutor executor = decodeJob.willDecodeFromCache()
        ? diskCacheExecutor
        : getActiveSourceExecutor();
    executor.execute(decodeJob);
  }

DecodeJob是一个Runnable任务,EnginJob将其提交给了线程池,所以我们直接看它的run()即可:

DecodeJob:
  public void run() {
    try {
...
      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;
    }
  }

  /**
   * Why we're being executed again.
   */
  private enum RunReason {
    /** The first time we've been submitted. */
    INITIALIZE,
    /**
     * We want to switch from the disk cache service to the source executor.
     */
    SWITCH_TO_SOURCE_SERVICE,
    /**
     * We retrieved some data on a thread we don't own and want to switch back to our thread to
     * process the data.
     */
    DECODE_DATA,
  }

在第一种情况中,首先调用了getNextGenerator()获得一个DataFetcherGenerator对象,DataFetcherGenerator 是一个接口,有三个具体的实现:

  • ResourceCacheGenerator: 资源文件
  • DataCacheGenerator: 缓存文件
  • SourceGenerator: 网络文件
DecodeJob:
  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;
      }
    }
  }

在runGenerators中会调用startNext(),因为第一次会从网络加载,看一下SourceGenerator的实现

SourceGenerator
  private volatile ModelLoader.LoadData<?> loadData;
  private final DecodeHelper<?> helper;

  @Override
  public boolean startNext() {
    if (dataToCache != null) {
      Object data = dataToCache;
      dataToCache = null;
      cacheData(data);
    }

    if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
      return true;
    }
    sourceCacheGenerator = null;

    loadData = null;
    boolean started = false;
    while (!started && hasNextModelLoader()) {
      loadData = helper.getLoadData().get(loadDataListIndex++);
      if (loadData != null
          && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
          || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
        started = true;
         //  分析1
        loadData.fetcher.loadData(helper.getPriority(), this);
      }
    }
    return started;
  }
  • 调用loadData内部的DataFetcher的loadData(),这里是发起网络请求的地方:
HttpUrlFetcher.load()
  @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);
    } 
  }

这里通过loadDataWithRedirects()获取一个流,再通过一个回调通知上层网络数据获取到了,在loadDataWithRedirects()中,使用的HttpURLConnection
这个回调是通知SourceGenerator的,因为上文分析1那边传了this

SourceGenerator:
  public void onDataReady(Object data) {
    //  写入disk缓存
    DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
    if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
      dataToCache = data;
      // We might be being called back on someone else's thread. Before doing anything, we should
      // reschedule to get back onto Glide's thread.
      cb.reschedule();
    } else {
        // 回调给上一层
      cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher,
          loadData.fetcher.getDataSource(), originalKey);
    }
  }

这个回调时在DecodeJob中回调的:

DecodeJob:

接受到网络数据的stream后,在DecodeJob中的回调逻辑:调用decodeFromRetrievedData()

  @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();
      }
    }
  }


  private void decodeFromRetrievedData() {
...
    Resource<R> resource = null;
    try {
      //  分析1
      resource = decodeFromData(currentFetcher, currentData, currentDataSource);
    } catch (GlideException e) {
      e.setLoggingDetails(currentAttemptingKey, currentDataSource);
      throwables.add(e);
    }
    if (resource != null) {
      // 分析2
      notifyEncodeAndRelease(resource, currentDataSource);
    } else {
      runGenerators();
    }
  }

decodeFromData()这个方法,调了很多decode 相关的代码,这里就不贴了,最后调用了DecodePath类的transcoder接口

DecodePath:
  private final ResourceTranscoder<ResourceType, Transcode> transcoder;

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

这个ResourceTranscoder接口的实现类:


看名称应该可以大概知道和bitmap,gif的解码有关系;decode操作会生成一个BitmapResource对象,在这个BitmapResource中会有一个Bitmap对象;
  • 分析1:主要是对网络流进行解码获取Bitmap对象
  • 分析2:解码完成后,回调上层接口

在DecodeJob完成解码后调用了回调是EngineJob的onResourceReady():

EngineJob
  @Override
  public void onResourceReady(Resource<R> resource, DataSource dataSource) {
    this.resource = resource;
    this.dataSource = dataSource;
    MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();  //  发出handler
  }

在回调中发了一个Handler消息;

EngineJob
        case MSG_COMPLETE:
          job.handleResultOnMainThread();
          break;

  @Synthetic
  void handleResultOnMainThread() {
    stateVerifier.throwIfRecycled();
    if (isCancelled) {
      resource.recycle();
      release(false /*isRemovedFromQueue*/);
      return;
    } 
    engineResource = engineResourceFactory.build(resource, isCacheable);
    hasResource = true;

    engineResource.acquire();
    //  分析1
    listener.onEngineJobComplete(this, key, engineResource);

    for (int i = 0, size = cbs.size(); i < size; i++) {
      ResourceCallback cb = cbs.get(i);
      if (!isInIgnoredCallbacks(cb)) {
        engineResource.acquire();
        //  分析2
        cb.onResourceReady(engineResource, dataSource);
      }
    }
     // 释放资源
    engineResource.release();
    release(false /*isRemovedFromQueue*/);
  }
  • EngineJob也会掉一个上层接口,这个接口回调到了Engine 中:
Engine:
  public void onEngineJobComplete(EngineJob<?> engineJob, Key key, EngineResource<?> resource) {
    Util.assertMainThread();
    // A null resource indicates that the load failed, usually due to an exception.
    if (resource != null) {
      resource.setResourceListener(key, this);

      if (resource.isCacheable()) {
        activeResources.activate(key, resource);
      }
    }

    jobs.removeIfCurrent(key, engineJob);
  }
  • 分析2:回调onResourceReady接口,这个回调走到了SingleRequest
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) {
    // We must call isFirstReadyResource before setting status.
    boolean isFirstResource = isFirstReadyResource();
    status = Status.COMPLETE;
    this.resource = resource;

    isCallingCallbacks = true;
    try {
      boolean anyListenerHandledUpdatingTarget = false;
      if (requestListeners != null) {
        for (RequestListener<R> listener : requestListeners) {
          anyListenerHandledUpdatingTarget |=
              listener.onResourceReady(result, model, target, dataSource, isFirstResource);
        }
      }
      anyListenerHandledUpdatingTarget |=
          targetListener != null
              && targetListener.onResourceReady(result, model, target, dataSource, isFirstResource);

      if (!anyListenerHandledUpdatingTarget) {
        Transition<? super R> animation =
            animationFactory.build(dataSource, isFirstResource);
        //  分析1
        target.onResourceReady(result, animation);
      }
    }

    notifyLoadSuccess();
  }
  • 分析1:在这边调用了Target接口的onResourceReady(),Target接口上文有介绍,我们这里看一下Target接口的实现类ImageViewTarget类的onResourceReady()是如何处理的:
ImageViewTarget
  @Override
  public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
    if (transition == null || !transition.transition(resource, this)) {
      setResourceInternal(resource);
    } else {
      maybeUpdateAnimatable(resource);
    }
  }


 /**
   *这里省略了中间方法的传递,最终调用:
   */

  protected void setResource(Bitmap resource) {
    view.setImageBitmap(resource);
  }

最终调用ImageView的setImageBitmap()设置bitmap;

Engine的逻辑

看了一周终于走通了,本文参考文章:

Android图片加载框架最全解析(一),Glide的基本用法

Glide架构设计艺术

Glide源码-加载任务

Glide 系列(三) Glide源码整体流程梳理

相关文章

网友评论

      本文标题:Glide ① — with,load,into

      本文链接:https://www.haomeiwen.com/subject/jlixjktx.html