Glide生命周期管理

栏目: Android · 发布时间: 5年前

内容简介:图片加载时只需调用以下代码,其中包含应用进入后台,图片会暂停加载的策略。通过这篇文章,探究上面的

图片加载时只需调用以下代码, Glide 就会全自动完成下载、缓存、缩放、展示等流程。

Glide.with(this)
        .load("http://www.abc.com")
        .into(imageView)

其中包含应用进入后台,图片会暂停加载的策略。通过这篇文章,探究 Glide 是如何实现开发者不主动触发逻辑,就能达到任务生命周期自动管理的奥秘。

Glide

上面的 Glide.with(this) 根据传入实参类型,例如: FragmentActivityFragmentContext 等不同选择目标重载方法。这里选择 FragmentActivity 进行解析,因为 AppCompatActivity 的父类是 FragmentActivity

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

先获取 Glide 单例,然后从这个单例里获取 RequestManagerRetriever 的实例。

private static RequestManagerRetriever getRetriever(@Nullable Context context) {
  // Context could be null for other reasons (ie the user passes in null), but in practice it will
  // only occur due to errors with the Fragment lifecycle.
  Preconditions.checkNotNull(
      context,
      "You cannot start a load on a not yet attached View or a Fragment where getActivity() "
          + "returns null (which usually occurs when getActivity() is called before the Fragment "
          + "is attached or after the Fragment is destroyed).");
  return Glide.get(context).getRequestManagerRetriever();
}

RequestManagerRetriever

忽略 Glide 首次初始化流程,终于从 RequestManagerRetriever 获取 RequestManager 实例。

public RequestManager get(@NonNull FragmentActivity activity) {
  // 前后台判断
  if (Util.isOnBackgroundThread()) {
    return get(activity.getApplicationContext());
  } else {
    assertNotDestroyed(activity);
    // 从Activity实例获取FragmentManager
    FragmentManager fm = activity.getSupportFragmentManager();
    return supportFragmentGet(activity, fm, null, isActivityVisible(activity));
  }
}

从上面可见,条件判断语句根据应用是否在前台走分支。因为本文关心是应用在前台的逻辑,所以直接走 else

进入分支后可见从 Activity 实例获取 FragmentManager

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) {
    Glide glide = Glide.get(context);
    requestManager =
        factory.build(
            glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
    current.setRequestManager(requestManager);
  }
  return requestManager;
}

以下方法从 ActivityFragmentManager 中查找是否存在名为 FRAGMENT_TAGFragment 实例。这个实例相当于一个隐形的钩子,挂在 Activity 监听界面生命周期变化,并回调 Glide 图片加载策略。

static final String FRAGMENT_TAG = "com.bumptech.glide.manager";

实例不存在就创建 Fragment 实例,这个实例类型为 SupportRequestManagerFragment

private SupportRequestManagerFragment getSupportRequestManagerFragment(
    @NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
  SupportRequestManagerFragment current =
      (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
  // 判断实例为空则需构建Fragment实例并加入到Activity
  if (current == null) {
    // 用FragmentManager获取SupportRequestManagerFragment实例
    current = pendingSupportRequestManagerFragments.get(fm);
    if (current == null) {
      // 创建新实例
      current = new SupportRequestManagerFragment();
      current.setParentFragmentHint(parentHint);
      // Activity可见,触发Fragment的onStart()逻辑调用
      if (isParentVisible) {
        current.getGlideLifecycle().onStart();
      }
      pendingSupportRequestManagerFragments.put(fm, current);
      // 把SupportRequestManagerFragment加入到Activity的FragmentManager中
      fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
      handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
    }
  }
  return current;
}

所有创建的 SupportRequestManagerFragment 都保存在以下哈希表中

final Map<FragmentManager, SupportRequestManagerFragment> pendingSupportRequestManagerFragments = new HashMap<>();

SupportRequestManagerFragment

接下来看看上面提及的 SupportRequestManagerFragment 。从签名可知继承父类 Fragment ,但不像一般 Fragment 包含填充的UI界面,而是仅包含生命周期的相关回调操作。说白了,就是借用 Fragment 达到监听 Activity 生命周期的目标。

public class SupportRequestManagerFragment extends Fragment {
  // 生命周期回调
  private final ActivityFragmentLifecycle lifecycle;
  private final RequestManagerTreeNode requestManagerTreeNode =
      new SupportFragmentRequestManagerTreeNode();
  private final Set<SupportRequestManagerFragment> childRequestManagerFragments = new HashSet<>();

  @Nullable private SupportRequestManagerFragment rootRequestManagerFragment;
  @Nullable private RequestManager requestManager;
  @Nullable private Fragment parentFragmentHint;

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

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

  @Override
  public void onAttach(Context context) {
    super.onAttach(context);
    try {
      registerFragmentWithRoot(getActivity());
    } catch (IllegalStateException e) {
      // OnAttach can be called after the activity is destroyed, see #497.
    }
  }
    
  // 注意下面不同生命周期对lifecycle的调用

  @Override
  public void onDetach() {
    super.onDetach();
    parentFragmentHint = null;
    unregisterFragmentWithRoot();
  }

  @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

最后进入 ActivityFragmentLifecycle 实现类,这个类其实就是观察者模式的具体实现。所有需要加载图片的任务,自行创建 LifecycleListener 放入 ActivityFragmentLifecycle 中。

class ActivityFragmentLifecycle implements Lifecycle {
  // 监听器集合
  private final Set<LifecycleListener> lifecycleListeners =
      Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>());
  private boolean isStarted;
  private boolean isDestroyed;

  // 把给定的监听器添加到监听器列表,以便接收生命周期事件的通知
  // 最新的生命周期事件会在所有注册的监听器上触发
  // 若activity或fragment被stop,会调用LifecycleListener.onStop()
  // onStart和onDestroy生命周期有类似操作
  @Override
  public void addListener(@NonNull LifecycleListener listener) {
    lifecycleListeners.add(listener);

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

  @Override
  public void removeListener(@NonNull 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();
    }
  }
}

最后,定制的 Fragment 监听 Activity 生命周期变化,告知 ActivityFragmentLifecycle ,随后 ActivityFragmentLifecycle 回调所有注册的监听器,实现应用进入后台暂停加载等功能。

总结

通过上述流程可知, Glide 的图片加载生命周期管理依赖传入的实例。

如果实例类型为 ActivityGlide 就能向里面注册一个没有界面的 Fragment 达到监听生命周期变化的目的。所以,该参数应尽可能传入 ActivityFragment 对象,最少也得是 View 持有的 Context ,而不是 ApplicationContext

Glide生命周期管理

最后, Glide 监听界面生命周期变化没有什么奥秘,就是把定制的 Fragment 添加到图片所在的 Activity 中,利用系统机制监听周期变化,在不同周期的不同加载操作。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

并行计算导论

并行计算导论

Ananth Grama、George Karypis、张武、毛国勇、Anshul Gupta、Vipin Kumar、程海英 / 张武、毛国勇、程海英 / 机械工业出版社 / 2005-1-1 / 49.00元

《并行计算导论》(原书第2版)全面介绍并行计算的各个方面,包括体系结构、编程范例、算法与应用和标准等,涉及并行计算的新技术,也覆盖了较传统的算法,如排序、搜索、图和动态编程等。《并行计算导论》(原书第2版)尽可能采用与底层平台无关的体系结构并且针对抽象模型来设计处落地。书中选择MPI、POSIX线程和OpenMP作为编程模型,并在不同例子中反映了并行计算的不断变化的应用组合。一起来看看 《并行计算导论》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

随机密码生成器
随机密码生成器

多种字符组合密码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试