美文网首页
Glide源码探究(一) - 生命周期绑定与Request创建

Glide源码探究(一) - 生命周期绑定与Request创建

作者: Bfmall | 来源:发表于2021-04-20 22:25 被阅读0次

    参考系列文章:

    蛮久之前囫囵吞枣地瞄过Glide部分源码,最近由于某个契机又心血来潮比较系统的过了一遍它的源码,发现它的蛮多设计还是比较有意思的(该系列笔记基于Glide 4.12.0这个版本进行分析)。

    首先Glide的使用十分简单,只需要三行代码就能完成图片的下载、缓存和显示:

    Glide.with(this)
        .load(url)
        .into(img)
    
    

    但为了我们可以方便的使用,实际上每一行代码的背后都帮我们做了不少脏活累活。

    Glide.with

    我们一行行来看,首先看Glide.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.getContext()).get(fragment);
    }
    
    public static RequestManager with(@NonNull android.app.Fragment fragment) {
      return getRetriever(fragment.getActivity()).get(fragment);
    }
    
    public static RequestManager with(@NonNull View view) {
      return getRetriever(view.getContext()).get(view);
    }
    
    

    内容大同小异,都是用getRetriever方法获取RequestManagerRetriever,然后从里面get出RequestManager。

    Glide 单例模式实现

    追踪getRetriever方法,可以比较容易看出来实际上是从Glide单例里面获取RequestManagerRetriever,而且我们还能看到Glide使用的是单例模式的双重校验锁方式:

    private static RequestManagerRetriever getRetriever(@Nullable Context context) {
            ...
        return Glide.get(context).getRequestManagerRetriever();
    }
    
    public static Glide get(@NonNull Context context) {
        if (glide == null) {
          ...
          synchronized (Glide.class) {
            if (glide == null) {
              checkAndInitializeGlide(context, annotationGeneratedModule);
            }
          }
        }
    
        return glide;
    }
    
    

    Glide生命周期绑定

    glide其实已经帮我们对activty生命周期进行了绑定:在onStop的时候停止加载,在onStart的时候继续加载,在onDestory清除任务和进行缓存的回收。它的原理是通过在Activity里面添加一个不可见的fragment,在里面监听生命周期。

    我们可以看到在RequestManagerRetriever.get方法最终会add一个SupportRequestManagerFragment到Activity里面:

    public RequestManager get(@NonNull FragmentActivity activity) {
        ...
        FragmentManager fm = activity.getSupportFragmentManager();
        return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
        ...
    }
    
    @NonNull
    private RequestManager supportFragmentGet(Context context, FragmentManager fm, Fragment parentHint, boolean isParentVisible) {
        SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);
        RequestManager requestManager = current.getRequestManager();
        ...
        return requestManager;
    }
    
    @NonNull
    private SupportRequestManagerFragment getSupportRequestManagerFragment(final FragmentManager fm, Fragment parentHint) {
        SupportRequestManagerFragment current = (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
        if (current == null) {
            ...
            current = new SupportRequestManagerFragment();
            ...
            fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
            ...
        }
        return current;
    }
    
    

    SupportRequestManagerFragment里面有个lifecycle成员,我们可以向它注册监听,RequestManager也正是这么干的:

    public class SupportRequestManagerFragment extends Fragment {
        ...
      private final ActivityFragmentLifecycle lifecycle;
      ...
      public SupportRequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
        this.lifecycle = 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();
      }
      ...
    }
    
    
    //RequestManager
    RequestManager(
          Glide glide,
          Lifecycle lifecycle,
          RequestManagerTreeNode treeNode,
          RequestTracker requestTracker,
          ConnectivityMonitorFactory factory,
          Context context) {
        ...
        lifecycle.addListener(connectivityMonitor);
        ...
    }
    
    public synchronized void onStart() {
        resumeRequests();
        targetTracker.onStart();
    }
    
    @Override
    public synchronized void onStop() {
        pauseRequests();
        targetTracker.onStop();
    }
    
    @Override
    public synchronized void onDestroy() {
        targetTracker.onDestroy();
        for (Target<?> target : targetTracker.getAll()) {
          clear(target);
        }
        targetTracker.clear();
        requestTracker.clearRequests();
        ...
    }
    
    

    这种添加不可见Fragment监听生命周期的技巧还是挺实用的。RxPermissions里面也用了这种技巧去监听onActivityResult回调

    RequestManager.load

    第二行的load方法,虽然只有一行但是实际上它做了两件事情:

    public RequestBuilder<Drawable> load(@Nullable String string) {
        return asDrawable().load(string);
    }
    
    
    1. new了一个请求Drawable的RequestBuilder:
    public RequestBuilder<Drawable> asDrawable() {
        return as(Drawable.class);
    }
    
    public <ResourceType> RequestBuilder<ResourceType> as(
          @NonNull Class<ResourceType> resourceClass) {
        return new RequestBuilder<>(glide, this, resourceClass, context);
    }
    
    
    1. 往builder里设置了model:
    public RequestBuilder<TranscodeType> load(@Nullable String string) {
        return loadGeneric(string);
    }
    private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
        ...
        this.model = model;
        ...
    }
    
    

    没错这里使用的是Builder模式。

    RequestBuilder.into

    into实际上也是干了两件事情,build了一个Request出来,然后runRequest执行它:

    // RequestBuilder
    public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
        ...
        return into(
            glideContext.buildImageViewTarget(view, transcodeClass),
            /*targetListener=*/ null,
            requestOptions,
            Executors.mainThreadExecutor());
    }
    
    private <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @Nullable RequestListener<TranscodeType> targetListener,
      BaseRequestOptions<?> options,
      Executor callbackExecutor) {
        ...
        Request request = buildRequest(target, targetListener, options, callbackExecutor);
        ...
      target.setRequest(request);
        requestManager.track(target, request);
        return target;
    }
    
    // RequestManager
    synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
        targetTracker.track(target);
        requestTracker.runRequest(request);
    }
    
    

    这里其实还有个细节,我们展开讲讲。如果我们中途想取消对该view的图片加载,可以用下面两行代码进行取消:

    Glide.with(this)
        .clear(img)
    
    

    这样就要求我们要记录view和request的关联,可能有些同学会想到用map<View,Request>这样的形式去保存,但是这样的话需要我们额外做出一些手段去防止view的内存泄露(如弱引用等)。其实安卓里比较常用的手段是将需要关联的东西用setTag方法保存到view里面:

    // ViewTarget
    public void setRequest(@Nullable Request request) {
        setTag(request);
    }
    
    private void setTag(@Nullable Object tag) {
        isTagUsedAtLeastOnce = true;
        view.setTag(tagId, tag);
    }
    
    

    于是clear的时候只需要用View.getTag把request再拿出来就好:

    public void clear(@NonNull View view) {
        clear(new ClearTarget(view));
    }
    
    public void clear(@Nullable final Target<?> target) {
        if (target == null) {
          return;
        }
        untrackOrDelegate(target);
    }
    
    private void untrackOrDelegate(@NonNull Target<?> target) {
        boolean isOwnedByUs = untrack(target);
      Request request = target.getRequest();
      if (!isOwnedByUs && !glide.removeFromManagers(target) && request != null) {
          target.setRequest(null);
          request.clear();
      }
    }
    
    

    request的执行

    runRequest的逻辑其实也比较简单,如果没有pause就begin request,如果不是就放到pendingRequests列表里面等待后面再begin:

    public void runRequest(@NonNull Request request) {
        requests.add(request);
        if (!isPaused) {
            request.begin();
        } else {
            request.clear();
            ...
            pendingRequests.add(request);
        }
    }
    
    

    而request的begin方法的核心流程就是先获取图片的尺寸,然后使用engine.load去启动真正的加载逻辑:

    public void begin() {
        ...
        if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
            onSizeReady(overrideWidth, overrideHeight);
        } else {
            target.getSize(this);
        }
        ...
    }
    
    public void onSizeReady(int width, int height) {
        ...
        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,
              callbackExecutor);
        ...
    }
    
    

    到这里其实一切都比较好理解,下一步就到了Engine这个Glide的核心模块,Glide的实际加载和多级缓存都是由它去调度的,由于该模块比较复杂,我们留到下一篇单独来聊。

    作者:嘉伟咯
    链接:https://www.jianshu.com/p/85da220d8442
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    相关文章

      网友评论

          本文标题:Glide源码探究(一) - 生命周期绑定与Request创建

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