Android 【手撕Glide】--Glide是如何关联生命周期的?

code小生 一个专注大前端领域的技术平台公众号回复Android加入安卓技术群

作者:唠嗑008
链接:https://www.jianshu.com/p/79dd4953ec25
声明:本文已获唠嗑008授权发表,转发等请联系原作者授权

熟悉Glide的同学都知道,Glide加载图片是和Activity/Fragment生命周期相关联的,具体来说在onStart()去发起请求或者重新请求、 onStop()去暂停正在进行的请求、 onDestory()去取消清除请求。这样的好处是节约资源、避免内存泄漏。本文源码解析基于Glide 4.6.1

系列文章

Android 【手撕Glide】--Glide缓存机制

Android 【手撕Glide】--Glide缓存机制(面试)

Android 【手撕Glide】--Glide是如何关联生命周期的?

学习指引

下面通过2部分来讲解生命周期相关知识

  • 1、以Glide.with(activity)为例讲解Glide是如何关联生命周期的;

  • 2、在1中为了降低理解Glide生命周期的难度,去掉了部分分支和细节,这一部分在2中补充。

时间紧张的朋友可以只看1就足以学会Glide生命周期原理了;时间充裕的朋友,建议你看看2中更详细的补充,这可以帮你更好的理解这个框架在设计上的优美。

一、 关联生命周期的核心类

  • Glide:供外部调用的核心类,外观模式;

  • RequestManagerRetriever:是关联RequestManager和SupportRequestManagerFragment/RequestManagerFragment的中间类;

  • RequestManager:是用来加载、管理图片请求的,会结合Activity/Fragment生命周期对请求进行管理;

  • SupportRequestManagerFragment/RequestManagerFragment:Glide内部创建无UI的fragment,会与当前Activity绑定,与RequestManager绑定,传递页面的生命周期。其中SupportRequestManagerFragment是v4包下的Fragment,RequestManagerFragment:Glide是android.app.Fragment;

  • ActivityFragmentLifecycle:保存fragment和Requestmanager映射关系的类,管理LifecycleListener;

  • LifecycleListener:定义生命周期管理方法的接口,onStart(), onStop(), onDestroy()。

二、关联生命周期的核心流程

这部分主要讲RequestManager加载/管理请求的时候是如何感知当前Activity/Fragment生命周期的。

Glide加载图片最基本的方式

Glide.with(context).load("xxx")into(imageView);

with()方法这个方法有多个重载,可以传入Context、Activity、Fragment、View等,但是内部调用方法都是一样的,只是参数有所不同,这里以传入FragmentActivity为例。

@NonNull
  public static RequestManager with(@NonNull FragmentActivity activity) {
    return getRetriever(activity).get(activity);
  }

这里先获取类RequestManagerRetriever对象,然后调用了它的get()方法。

RequestManagerRetriever#get()

@NonNull
  public RequestManager get(@NonNull FragmentActivity activity) {
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      //获取当前Activity的FragmentManager
      //用于后续将创建的Fragment绑定到activity
      FragmentManager fm = activity.getSupportFragmentManager();
      return supportFragmentGet(activity, fm, null /*parentHint*/);
    }
  }

这里先判断是否在子线程,这个分支先不讲,先看看在主线程中的逻辑:先获取当前Activity的FragmentManager,,然后调用supportFragmentGet()

RequestManagerRetriever#supportFragmentGet()

@NonNull
  private RequestManager supportFragmentGet(@NonNull Context context, @NonNull FragmentManager fm,
      @Nullable Fragment parentHint) {
    //创建无UI的Fragment,并绑定到当前activity
    SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
      // TODO(b/27524013): Factor out this Glide.get() call.
      Glide glide = Glide.get(context);
      //创建RequestManager,获取fragment的lifecycle,传入requestManager
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }

RequestManagerRetriever#getSupportRequestManagerFragment()

@NonNull
  SupportRequestManagerFragment getSupportRequestManagerFragment(
      @NonNull final FragmentManager fm, @Nullable Fragment parentHint) {
    //1、由FragmentManager通过tag获取fragment
    SupportRequestManagerFragment current =
        (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      //2、从缓存集合中获取fragment的,map以fragmentManger为key,
      //以fragment为value进行存储
      current = pendingSupportRequestManagerFragments.get(fm);
      if (current == null) {
        //3、创建一个fragment实例
        current = new SupportRequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        pendingSupportRequestManagerFragments.put(fm, current);
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }

1、创建无UI的Fragment,并绑定到当前activity;2、通过builder模式创建RequestManager,并且将fragment的lifecycle传入,这样Fragment和RequestManager就建立了联系; 3、获取Fragment对象,先根据tag去找,如果没有从内存中查找,pendingSupportRequestManagerFragments是一个存储fragment实例的HashMap,再没有的话就new一个。

SupportRequestManagerFragment的核心方法

public class SupportRequestManagerFragment extends Fragment {
  private static final String TAG = "SupportRMFragment";
  private final ActivityFragmentLifecycle lifecycle;

    ...

  public SupportRequestManagerFragment() {
    this(new ActivityFragmentLifecycle());
  }

  @VisibleForTesting
  @SuppressLint("ValidFragment")
  public SupportRequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
    this.lifecycle = lifecycle;
  }

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

ActivityFragmentLifecycle# onStart()

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

1、在创建Fragment的时候会创建ActivityFragmentLifecycle对象;2、在Fragment生命周期的方法中会调用Lifecycle的相关方法来通知RequestManager;3、LifecycleListener 是一个接口,Lifecycle最终是调用了lifecycleListener来通知相关的实现类的,也就是RequestManager。

RequestManager类的关键部分

public class RequestManager implements LifecycleListener {
/**
   * Lifecycle callback that registers for connectivity events (if the
   * android.permission.ACCESS_NETWORK_STATE permission is present) and restarts failed or paused
   * requests.
   */
  @Override
  public void onStart() {
    resumeRequests();
  }

  /**
   * Lifecycle callback that unregisters for connectivity events (if the
   * android.permission.ACCESS_NETWORK_STATE permission is present) and pauses in progress loads.
   */
  @Override
  public void onStop() {
    pauseRequests();
  }

  /**
   * Lifecycle callback that cancels all in progress requests and clears and recycles resources for
   * all completed requests.
   */
  @Override
  public void onDestroy() {
    ...
    requestTracker.clearRequests();
  }
}
小结

1、创建一个无UI的Fragment,具体来说是SupportRequestManagerFragment/RequestManagerFragment,并绑定到当前Activity,这样Fragment就可以感知Activity的生命周期;

2、在创建Fragment时,初始化Lifecycle、LifecycleListener,并且在生命周期的onStart() 、onStop()、 onDestroy()中调用相关方法;

3、在创建RequestManager时传入Lifecycle 对象,并且LifecycleListener实现了LifecycleListener接口;

4、这样当生命周期变化的时候,就能通过接口回调去通知RequestManager处理请求。

三、关联生命周期相关补充

还记得在介绍RequestManagerRetriever#get()方法获取RequestManager对象时我们传入的参数是FragmentActivity吗?实际上这个方法有多个重载:

RequestManager get(@NonNull Context context) {}
RequestManager get(@NonNull FragmentActivity activity) {}
RequestManager get(@NonNull Fragment fragment) {}
RequestManager get(@NonNull Activity activity) {}
RequestManager get(@NonNull View view) {}

虽然有多个重载,但是总体上只有2种情况,即传入的是否为Application类型参数。

  @NonNull
  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());
      }
    }
    //子线程或者传入Application Context
    return getApplicationManager(context);
  }

1、传入Application Context或者在子线程使用:调用getApplicationManager(context);这样Glide的生命周期就和应用程序一样了。

@NonNull
  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.

          // TODO(b/27524013): Factor out this Glide.get() call.
          Glide glide = Glide.get(context.getApplicationContext());
          applicationManager =
              factory.build(
                  glide,
                  new ApplicationLifecycle(),
                  new EmptyRequestManagerTreeNode(),
                  context.getApplicationContext());
        }
      }
    }

    return applicationManager;
  }

这里获取RequestManager对象的方式和之前传入Activity、Fragment对象是有所区别的,之前是创建了一个SupportRequestManagerFragment/RequestManagerFragment对象,然后获取其内部创建的Lifecycle对象作为参数传到RequestManager;而这里的主要差异是获取Lifecycle对象不一样,用的是ApplicationLifecycle,由于没有创建Fragment,这里只会调用onStart(),这种情况Glide生命周期就和Application一样长了。

class ApplicationLifecycle implements Lifecycle {
  @Override
  public void addListener(@NonNull LifecycleListener listener) {
    listener.onStart();
  }

  @Override
  public void removeListener(@NonNull LifecycleListener listener) {
    // Do nothing.
  }
}

2、其它情况,比如传入Activity、Fragment等:最后只会调用fragmentGet() 、或者supportFragmentGet()中的一个,这样Glide就可以关联生命周期,会在生命周期不同的方法中对请求做不同的处理。

@NonNull
  private RequestManager supportFragmentGet(@NonNull Context context, @NonNull FragmentManager fm,
      @Nullable Fragment parentHint) {
    //创建无UI的Fragment,并绑定到当前activity
    SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
      // TODO(b/27524013): Factor out this Glide.get() call.
      Glide glide = Glide.get(context);
      //创建RequestManager,获取fragment的lifecycle,传入requestManager
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      //fragment与RequestManager关联
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }
@NonNull
  private RequestManager fragmentGet(@NonNull Context context,
      @NonNull android.app.FragmentManager fm,
      @Nullable android.app.Fragment parentHint) {
    RequestManagerFragment current = getRequestManagerFragment(fm, parentHint);
    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;
  }

2个方法等实现其实都是一样的,唯一的区别是supportFragmentGet创建的是v4包下的Fragment,fragmentGet创建的是android.app.Fragment。

RequestManagerRetriever#getSupportRequestManagerFragment()

@NonNull
  SupportRequestManagerFragment getSupportRequestManagerFragment(
      @NonNull final FragmentManager fm, @Nullable Fragment parentHint) {
    //1、由FragmentManager通过tag获取fragment
    SupportRequestManagerFragment current =
        (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      //2、从缓存集合中获取fragment的,map以fragmentManger为key,
      //以fragment为value进行存储
      current = pendingSupportRequestManagerFragments.get(fm);
      if (current == null) {
        //3、创建一个fragment实例
        current = new SupportRequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        //将创建的Fragment放入HashMap缓存
        pendingSupportRequestManagerFragments.put(fm, current);
        //提交事物,将fragment绑定到Activity
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
   //发消息,从map缓存中删除fragment
   handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }

@Override
  public boolean handleMessage(Message message) {
   ...
    switch (message.what) {
      case ID_REMOVE_SUPPORT_FRAGMENT_MANAGER:
        FragmentManager supportFm = (FragmentManager) message.obj;
        key = supportFm;
        //从map缓存中删除fragment
        removed = pendingSupportRequestManagerFragments.remove(supportFm);
        break;
  }

看一下这里获取Fragment的流程,首先由FragmentManager通过tag获取;如果没有就从pendingSupportRequestManagerFragments这个Map从获取;再没有的话就new一个SupportRequestManagerFragment对象,并且把fragment对象放入map缓存起来,接着通过FragmentManager将fragment与activity绑定,但是紧接着又调用handle发送了一条消息。

这里有个问题很奇怪,刚把创建的fragment对象放入map缓存起来,但是马上又通过handler把它删除,这是什么情况?

原因是这样的,当调用FragmentManager的add()方法时,是通过开启事务的方式来进行绑定的,这个过程是异步的,具体来说,就是调用add方法时,并不是马上就和activity绑定好了,而是通过Hander来处理的。

下面来看一种应用场景

@Override
    protected void onStart() {
        super.onStart();
        Glide.with(this).load("xx").into(image1);
        Glide.with(this).load("xx").into(image2);
    }

1、在第一次调用第一行代码的时候,会生成一个Fragment对象,通过FragmentManager出发Fragment于Activity绑定,这个绑定过程是通过Handler发消息来完成的,假设这个消息为m1;

2、紧接着使用Handler来发送消息从HashMap中删除刚才保存的Fragment,假设这个消息为m2;

3、由于是异步的,在消息未处理之前已经开始执行第二行Glide代码了,具体说可能是m1,m2还没有处理,就已经开始调用getSupportRequestManagerFragment方法了,这个方法内部是获取Fragment对象的,具体分析上面说过了;如果不用map来缓存fragment,那么代码流程应该是这样的

不使用map获取fragment

此时通过findFragmentByTag还没有找到Fragment,就会重新生成一个Fragment,这是Glide所不允许的,每一个Activity或者Fragment在使用Glide时,只能有一个所依附的虚拟的Fragment。所以将之前所生成的Fragment存储到HashMap中,这样就不会重复生成。等到SupportRequestManagerFragment与Activity绑定完成后,也就是消息m1处理完成后,再将Fragment从Map中销毁。

总结

1、在使用Glide的时候尽量传入Activity或者Fragment的,这样才能绑定/关联生命周期;使用ApplicationContext的话会使得Glide生命周期和Application一样长;

2、在UI线程中调用Glide,在子线程使用的话会和使用ApplicationContext一样;

3、Glide关联生命周期主要分为2个部分:如何感应当前页面的生命周期?通过创建一个无UI的Fragment来实现;如何传递生命周期?RequestManager与Fragment之间通过Lifecycle、LifecycleListener接口回调的方式来实现。更详细的可以看第二部分的小结。

4、一个疑问:为什么Glide不通过Google的Lifecycle来实现RequestManager关联生命周期呢?这个库自sdk26就继承到Android源码的Activity/Fragment中了。

参考:

https://www.jianshu.com/p/b7d895b9f32c https://www.jianshu.com/p/4ab09771aed1 https://www.jianshu.com/p/bb08d5fb97ae

相关阅读

1 Android项目重构实践:从 Fresco 到 Glide 低成本重构方案
2 Glide 架构设计艺术
3 Android Glide缓存策略分析
4 Android 基于 glide 4.0 封装图片加载库
5 Glide 加载图片实现进度条效果

如果你有写博客的好习惯

欢迎投稿

点个在看,小生感恩❤️

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值