内容简介:图片加载时只需调用以下代码,其中包含应用进入后台,图片会暂停加载的策略。通过这篇文章,探究上面的
图片加载时只需调用以下代码, 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 监听界面生命周期变化没有什么奥秘,就是把定制的 Fragment 添加到图片所在的 Activity 中,利用系统机制监听周期变化,在不同周期的不同加载操作。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
JavaScript高级程序设计(第3版)
[美] Nicholas C. Zakas / 李松峰、曹力 / 人民邮电出版社 / 2012-3-29 / 99.00元
本书是JavaScript 超级畅销书的最新版。ECMAScript 5 和HTML5 在标准之争中双双胜出,使大量专有实现和客户端扩展正式进入规范,同时也为JavaScript 增添了很多适应未来发展的新特性。本书这一版除增加5 章全新内容外,其他章节也有较大幅度的增补和修订,新内容篇幅约占三分之一。全书从JavaScript 语言实现的各个组成部分——语言核心、DOM、BOM、事件模型讲起,深......一起来看看 《JavaScript高级程序设计(第3版)》 这本书的介绍吧!