Glide生命周期管理

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

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

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

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

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

Glide

上面的 Glide.with(this) 根据传入实参类型,例如: FragmentActivity 、 Fragment 、 Context 等不同选择目标重载方法。这里选择 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;
}

以下方法从 Activity 的 FragmentManager 中查找是否存在名为 FRAGMENT_TAG 的 Fragment 实例。这个实例相当于一个隐形的钩子,挂在 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 的图片加载生命周期管理依赖传入的实例。

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

Glide生命周期管理

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


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

查看所有标签

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

技术领导之路(中英文对照)

技术领导之路(中英文对照)

Gerald M.Weinberg / 余晟 / 电子工业出版社 / 2009-12 / 69.00元

《技术领导之路:全面解决问题的途径(中英文对照)》内容简介:搞定技术问题并不简单,但与人打交到也并非易事。作为一个技术专家,你是否在走上管理岗位时遇到了各种不适“症状”?《技术领导之路:解决问题的有机方法》一书将帮助你成为一个成功的解决问题的领导者。书中温伯格从一个反思者的角度阐述了要成为一个成功的解决问题的领导者必备的3个技能——MOI,即激励(Motivation)、组织(Organizati......一起来看看 《技术领导之路(中英文对照)》 这本书的介绍吧!

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

多种字符组合密码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器