Glide源代码分析(一)

一直想写这篇文章,总怕写得不好。第一步,就先简单分析下Glide的代码流程吧。首先,我们看看,是怎样使用Glide加载图片的。
 Glide.with(this)
 .load("https://goo.gl/images/r9XuWC")
 .into(iv);
可以看到,使用非常简单。那就简单分析下,每一步做了些什么事情。我打算分析下三个比较重要的方法。

Glide.with()

 public static RequestManager with(@NonNull FragmentActivity activity) {
    return getRetriever(activity).get(activity);
  }
可以看到,不管我们传入Activity,还是Fragment,最后都会通过RequestManagerRetriever返回一个RequestManager对象。那么RequestManagerRetriever,RequestManager是干什么的?

RequestManagerRetriever:用来创建新的RequestManager,或者从Activity,Fragment拿到已经存在的RequestManager。

RequestManager:Glide用来管理,开启Request的。

好了,知道了这两个的作用之后,我们看下这个with方法的内部实现。
getRetriever(activity).get(activity)
我们着重看一下RequestManagerRetriever的get方法:
 public RequestManager get(@NonNull FragmentActivity activity) {
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      FragmentManager fm = activity.getSupportFragmentManager();
      return supportFragmentGet(
          activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }
前面的判断逻辑我们跳过,着重分析下supportFragmentGet(activity, fm, /parentHint=/ null, isActivityVisible(activity))这句。
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;
  }
这个方法比较重要。总共做了三件事情。
  1. 创建SupportRequestManagerFragment;
  2. 创建RequestManager;
  3. 将SupportRequestManagerFragment与RequestManager绑定。
那么SupportRequestManagerFragment是干啥的呢?SupportRequestManagerFragment是一个无界面的Fragment,用来开启,停止,管理fragment,或者当前fragment的父Activity中Glide图片加载请求的。
在SupportRequestManagerFragment内部,可以看到一个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();
  }
在SupportRequestManagerFragment的生命周期中回调lifecycle的生命周期方法。
在创建RequestManager时,我们将SupportRequestManagerFragment内部的lifecycle传递进去。这样就将RequestManager的生命周期与Fragment,或者Activity的生命周期巧妙地结合起来。
 @Override
 public void onStart() {
    resumeRequests();
    targetTracker.onStart();
  }
  
   @Override
   public void onStop() {
    pauseRequests();
    targetTracker.onStop();
  }
  
  @Override
  public void onDestroy() {
    targetTracker.onDestroy();
    for (Target<?> target : targetTracker.getAll()) {
      clear(target);
    }
    targetTracker.clear();
    requestTracker.clearRequests();
    lifecycle.removeListener(this);
    lifecycle.removeListener(connectivityMonitor);
    mainHandler.removeCallbacks(addSelfToLifecycle);
    glide.unregisterRequestManager(this);
  }
  
这样,在RequestManager的生命周期中,我们可以开启,暂停,停止图片加载请求。这也是Glide设计比较巧妙的地方。

RequestManager.load()

可以看到,重载的load方法很多,但最后都是调用loadGeneric方法。
  private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
    this.model = model;
    isModelSet = true;
    return this;
  }
可以看到,就是进行一些数据简单的设置。

RequestBuilder.into()

private <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @Nullable RequestListener<TranscodeType> targetListener,
      @NonNull RequestOptions options) {
    Util.assertMainThread();
    Preconditions.checkNotNull(target);
    //(1)判断数据是否设置,就是我们load方法所做的事情
    if (!isModelSet) {
      throw new IllegalArgumentException("You must call #load() before calling #into()");
    }

    options = options.autoClone();
    Request request = buildRequest(target, targetListener, options);

    Request previous = target.getRequest();
    //(2)中间这部分,就是一些优化操作,熟悉主流程的话可以忽略。
    if (request.isEquivalentTo(previous)
        && !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
      request.recycle();
        previous.begin();
      }
      return target;
    }

    requestManager.clear(target);
    //(3)最后就是将Request请求与我们显示图片的目标Target进行绑定。
    target.setRequest(request);
    requestManager.track(target, request);

    return target;
  }
into方法里面有个比较重要的一句,requestManager.track(target, request)。我们进去看一下,里面做了什么事情。
  void track(@NonNull Target<?> target, @NonNull Request request) {
    targetTracker.track(target);
    requestTracker.runRequest(request);
  }
  
在TargetTracker内部,有一个弱引用的Target集合。当我们调用TargetTracker.track(Target),就将当前Target添加到Set集合中来。加进来干什么呢?就是在Target的生命周期回调中,执行Target的生命周期回调。所以说,targetTracker.track(target)就是对Target进行生命周期追踪管理的。
下面,我们看看 requestTracker.runRequest(request)这句代码做了什么事情。
  public void runRequest(@NonNull Request request) {
    requests.add(request);
    if (!isPaused) {
      request.begin();
    } else {
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "Paused, delaying request");
      }
      pendingRequests.add(request);
    }
  }
在这个RequestTracker里面,有两个Request的集合。
  private final Set<Request> requests =
      Collections.newSetFromMap(new WeakHashMap<Request, Boolean>());
  //未完成的Request集合
  private final List<Request> pendingRequests = new ArrayList<>();
在runRequest的时候,对RequestTracker的状态进行判断,如果已经暂停,那就加到pendingRequests里面,如果没有暂停,那就Request真正开始。这个地方的Request只是一个抽象的概念,到此一个简单的流程就分析结束了。在下一篇文章中,我想对这个抽象的Request内部进行详细的分析。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容