Glide源码解读(一)-- 图片加载的生命周期

先来看下glide的一般使用方法

Glide.with(context).load(url).into(mImageView);

其中Glide.with(context)这一步就完成了图片加载时的生命周期绑定,可见glide调用简单,然而其在背后的逻辑却很复杂,接下来我们从源码的角度去解读glide如何用一句话完成了这么多事。

我们以context对象是Activity为例,进入到Glide.with(context) 这个方法中

RequestManagerRetriever
public RequestManager get(@NonNull Activity activity) {
  if (Util.isOnBackgroundThread()) {
    // 如果不是主线程,则context对象转为ApplicationContext,然后也不做绑定生命周期的操作,
    // 图片加载的生命周期默认为Application的生命周期
    return get(activity.getApplicationContext());
  } else {
    assertNotDestroyed(activity);
    android.app.FragmentManager fm = activity.getFragmentManager();
    return fragmentGet(activity, fm, null /*parentHint*/);
  }
}

接着进入fragmentGet方法

private RequestManager fragmentGet(@NonNull Context context,
    @NonNull android.app.FragmentManager fm,
    @Nullable android.app.Fragment parentHint) {
  // 获取到一个无UI的Fragment,用来绑定Activity从而实现生命周期同步
  // 因为glide无法直接获取activity的生命周期,通过activity的FragmentManager中加入一个隐藏的fragment,
  // 因为fragment与传入的activity生命周期一致,所以只要监听这个RequestManagerFragment就能实现生命周期管理
  RequestManagerFragment current = getRequestManagerFragment(fm, parentHint);
  RequestManager requestManager = current.getRequestManager();
  ......
  return requestManager;
}

我们具体看下fragment的创建过程

RequestManagerFragment getRequestManagerFragment(
    @NonNull final android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint) {
  // 由于这个Fragment是个无UI的Fragment,可以通过findFragmentByTag(FRAGMENT_TAG)去查找这个RequestManagerFragment
  // 但如果第一次进来,current就是null,如果已经创建过,可以通过fm对象找到已有的fragment对象
  // 无UI查找Fragment参考文章 http://blog.csdn.net/llp1992/article/details/41828237
  RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
  if (current == null) {
    current = pendingRequestManagerFragments.get(fm);
    if (current == null) {
      // 初始化RequestManagerFragment并且绑定FRAGMENT_TAG放入FragmentManager
      current = new RequestManagerFragment();
      ......
    }
  }
  return current;
}

接着我们进入RequestManagerFragment的构造方法中查看初始化的时候做了些什么

public class SupportRequestManagerFragment extends Fragment {
  
  public SupportRequestManagerFragment() {
    // 初始化Fragment的时候也顺便初始化了ActivityFragmentLifecycle
    this(new ActivityFragmentLifecycle());
  }

  @SuppressLint("ValidFragment")
  public SupportRequestManagerFragment(ActivityFragmentLifecycle lifecycle) {
    // lifecycle赋值
    this.lifecycle = lifecycle;
  }

  /**
   * 在构造方法中{@link #SupportRequestManagerFragment(ActivityFragmentLifecycle)}
   * 初始化lifecycle
   */
  ActivityFragmentLifecycle getGlideLifecycle() {
    return 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();
  }
}

我们可以看下上面这个类的部分代码,在初始化Fragment的时候也顺带初始化了ActivityFragmentLifecycle,并赋值给lifecycle,在fragment的生命周期方法中,比如onStart方法中,调用了lifecycle.onStart(),由于fragment和绑定的activity生命周期基本一样,这样的话lifecycle对象也就带有刚开始传入Glide.with(context)这个context对象的生命周期,可以通过fragment对象的getGlideLifecycle()方法获取到这个带有生命周期的自定义类的对象。

到这里,基本就知道了glide怎么去获取到当前上下文对象的生命周期变化,接下去我们继续分析,glide获取到生命周期后去做了些什么事情。

首先来看下这个自定义的生命周期自定义类

class ActivityFragmentLifecycle implements Lifecycle {
  
  @Override
  public void addListener(LifecycleListener listener) {
    lifecycleListeners.add(listener);

    if (isDestroyed) {
      listener.onDestroy();
    } else if (isStarted) {
      listener.onStart();
    } else {
      listener.onStop();
    }
  }

  @Override
  public void removeListener(LifecycleListener listener) {
    lifecycleListeners.remove(listener);
  }

  void onStart() {
    isStarted = true;
    for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
      lifecycleListener.onStart();
    }
  }

  void onStop() {
    isStarted = false;
    for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
      lifecycleListener.onStop();
    }
  }

  void onDestroy() {
    isDestroyed = true;
    for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
      lifecycleListener.onDestroy();
    }
  }
}

public interface Lifecycle {
  void addListener(LifecycleListener listener);
  void removeListener(LifecycleListener listener);
}

ActivityFragmentLifecycle 实现了Lifecycle,对外暴露一个addListener方法,可以监听生命周期的变化。到这里,监听生命周期的准备工作都已经完成,就等其他想要使用的地方去实现这个监听器了,所以我们回过头去看下哪里实现了这个监听器。


接下来我们回到上文中的fragmentGet方法,刚刚看了部分代码,现在我把这个方法的全部代码贴出来

private RequestManager fragmentGet(@NonNull Context context,
    @NonNull android.app.FragmentManager fm,
    @Nullable android.app.Fragment parentHint) {
  // 获取到一个无UI的Fragment,用来绑定Activity从而实现生命周期同步
  // 因为glide无法直接获取activity的生命周期,通过activity的FragmentManager中加入一个隐藏的fragment,
  // 因为fragment与传入的activity生命周期一致,所以只要监听这个RequestManagerFragment就能实现生命周期管理
  RequestManagerFragment current = getRequestManagerFragment(fm, parentHint);
  RequestManager requestManager = current.getRequestManager();
  if (requestManager == null) {
    // 初始化了图片加载引擎等内容,为后面的图片加载做准备
    Glide glide = Glide.get(context);
    requestManager =
        factory.build(
            glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
    current.setRequestManager(requestManager);
  }
  return requestManager;
}

上面我们用大篇幅解析了这一行代码 RequestManagerFragment current = getRequestManagerFragment(fm, parentHint),接下去我们接着走下去。接着执行 RequestManager requestManager = current.getRequestManager(),当第一次执行 current.get 方法的时候,返回的 requestManager 对象是null,所以我们重点分析下if里面的代码块。

我们进入factory.build(glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context)方法中

public interface RequestManagerFactory {
  @NonNull
  RequestManager build(
      @NonNull Glide glide,
      @NonNull Lifecycle lifecycle,
      @NonNull RequestManagerTreeNode requestManagerTreeNode,
      @NonNull Context context);
}

private static final RequestManagerFactory DEFAULT_FACTORY = new RequestManagerFactory() {
  @NonNull
  @Override
  public RequestManager build(@NonNull Glide glide, @NonNull Lifecycle lifecycle,
      @NonNull RequestManagerTreeNode requestManagerTreeNode, @NonNull Context context) {
    // 在这里初始化RequestManager
    return new RequestManager(glide, lifecycle, requestManagerTreeNode, context);
  }
};

其中factoryRequestManagerRetriever构造方法中被赋值:this.factory = factory != null ? factory : DEFAULT_FACTORY,故 factory.build 最终执行的是return new RequestManager(glide, lifecycle, requestManagerTreeNode, context)。其中lifecycle正是我们前面创建fragment生成的带有生命周期的自定义类。

我们进入RequestManager的构造方法,查看下RequestManager整个类的关键代码

public class RequestManager implements LifecycleListener {

  RequestManager(
      Glide glide,
      Lifecycle lifecycle,
      RequestManagerTreeNode treeNode,
      RequestTracker requestTracker,
      ConnectivityMonitorFactory factory,
      Context context) {

    this.glide = glide;
    this.lifecycle = lifecycle;
    this.treeNode = treeNode;
    this.requestTracker = requestTracker;
    this.context = context;

    if (Util.isOnBackgroundThread()) {
      mainHandler.post(addSelfToLifecycle);
    } else {
      // RequestManager 实现了LifecycleListener,然后和lifecycle实现了绑定
      lifecycle.addListener(this);
    }
  }

  @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从类名来看,应该就是请求管理类,它自身实现了LifecycleListener,在自身的构造方法中,和lifecycle进行了绑定,这样我们先前初始化的fragment的生命周期就在这里实现了监听,我们可以看下RequestManager生命周期方法中的一些代码,resumeRequests()pauseRequests(),顾名思义,他在执行相应生命周期的时候做了重新发送请求、暂停请求、销毁请求等操作。

到这里,我们就对glide的生命周期有了完整的了解,图片在加载时,会根据传入context对象的生命周期变化而做出暂停、销毁请求等操作,其中实现的主要原理就是glide生成了一个没有UI的Fragment同步context对象的生命周期,然后对这个自定义的Fragment进行监听,从而处理其他加载逻辑。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,743评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,296评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,285评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,485评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,581评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,821评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,960评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,719评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,186评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,516评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,650评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,936评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,757评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,991评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,370评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,527评论 2 349

推荐阅读更多精彩内容

  • 那些 你以为 永远不会离开你的人 一但 离开 便是永恒 2017.7.21 上官楠
    上官楠阅读 162评论 2 5
  • 一起打败蛀牙大王第三集。那么前两集记得讲什么吗?不记得啦,第一集我们讲是说早晚要刷牙可以保护牙齿吗?第二集讲,如果...
    李灵军阅读 443评论 0 0
  • 2018.2.26 星期一 天气晴 今天我们吃过早饭,就带着小宝到门诊看医生。小宝还是发烧,这已经是发烧的第...
    收获之夜阅读 216评论 0 0