Glide 系列三:如何手写一个Glide 框架?
本文概述:
- 本文介绍了简易Glide 框架的搭建流程,但因Glide 框架过于复杂;做了大量简化,砍掉了部分代码;在文章末尾简单介绍了关于Glide 的一些零散问题;
手写基础:
- 需要深入理解Glide 整体架构,并清楚源码走向
- 手写时,去掉不必须的东西,在源码的基础上进行修改;
整体工程架构:
工具层:
- 来源自源码,代码过多,不便展开,如有需要请联系我
环境层:
-
有什么?
-
Glide.kt
-
设计思路:重写代码
- 重写一系列with() + get() 函数
-
设计思路:getRetriever()
- 声明RequestManagerRetriever ,因为这个是final 修饰的,所以必定是在构造函数中初始化
-
完整代码
package com.derry.dlifecycle.glide; import android.app.Activity; import android.content.Context; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; public class Glide { private static volatile Glide glide; //声明RequestManagerRetriever 对象,并在Glide 构造函数中初始化 private final RequestManagerRetriever requestManagerRetriever; public Glide(Context context) { this.requestManagerRetriever = new RequestManagerRetriever(); } @NonNull public static Glide get(@NonNull Context context) { if (glide == null) { synchronized (Glide.class) { if (glide == null) { glide = new Glide(context); } } } return glide; } //重写一系列with() @NonNull public static RequestManager with(@NonNull Context context) { return getRetriever(context).get(context); } @NonNull public static RequestManager with(@NonNull Activity activity) { return getRetriever(activity).get(activity); } @NonNull public static RequestManager with(@NonNull FragmentActivity activity) { return getRetriever(activity).get(activity); } @NonNull public static RequestManager with(@NonNull Fragment fragment) { // androidx Fragment return getRetriever(fragment.getContext()).get(fragment); } @SuppressWarnings("deprecation") @Deprecated @NonNull public static RequestManager with(@NonNull android.app.Fragment fragment) { // app.Fragment return getRetriever(fragment.getActivity()).get(fragment); } //到这个地方 @NonNull private static RequestManagerRetriever getRetriever(@Nullable Context context) { return Glide.get(context).getRequestManagerRetriever(); } @NonNull public RequestManagerRetriever getRequestManagerRetriever() { return requestManagerRetriever; } }
-
-
RequestManager.kt
-
官方源码亮点:
- 存在网络重连操作:比如,正在请求服务器但宿主被杀掉了,那么此时的请求就会加入等待队列;待恢复后,就会执行等待队列中的东西;
- 存在内存监控操作:当内存紧张时,释放某些内存
-
自定义完整代码:只要基础功能
-
接口选用Lifecycle 面向更高层
-
onStart():宿主可见
- Activity/Fragment 可见时恢复请求 (onStart() ) 掉用函数
- 运行队列 全部执行(beigin),等待队列 全部清空(clear)
-
onStop():宿主不可见
- Activity/Fragment 不可见时暂停请求 (onStop() ) 掉用函数
- 运行队列 全部停止,把任务都加入到等待队列
-
onDestroy:宿主被销毁
- 自己负责移除自己绑定的生命周期监听,释放操作
- 移除自己的监听
-
package com.derry.dlifecycle.glide; import android.content.Context; import android.util.Log; import com.derry.dlifecycle.glide.binding.ApplicationLifecycle; import com.derry.dlifecycle.glide.binding.inter.Lifecycle; import com.derry.dlifecycle.glide.binding.inter.LifecycleListener; import com.derry.dlifecycle.glide.util.LOG; public class RequestManager implements LifecycleListener { private Lifecycle lifecycle; // 构造函数 已经给自己注册了【自己给自己绑定】 public RequestManager(Glide glide, Lifecycle lifecycle, Context applicationContext) { this.lifecycle = lifecycle; this.lifecycle.addListener(this); } @Override public void onStart() { Log.d(LOG.TAG, "onStart: 运行队列 全部执行,等待队列 全部清空 ...."); } @Override public void onStop() { Log.d(LOG.TAG, "onStop: 运行队列 全部停止,把任务都加入到等待队列 ...."); } @Override public void onDestroy() { Log.d(LOG.TAG, "onDestroy: 自己负责移除自己绑定的生命周期监听,释放操作 ...."); this.lifecycle.removeListener(this); // 已经给自己销毁了 【自己给自己移除】 } }
-
-
RequestManagerRetriever
-
存在意义:专门管理RequestManager
-
设计思路:作用域
- Application 作用域
-
设计思路:共用的get()
- Activity、FragmentActivity 均可调用此函数,获得RequestManager 对象
-
设计思路:两种Fragment ,继承关系不同
- SupportRequestManagerFragment:androidx 的Fragment
- RequestManagerFragment:app 的Fragment
-
设计思路:绑定androidx 的Fragment (supportFragmentGet)
-
从 FragmentManager 中获取 SupportRequestManagerFragment(空白) ,注意是从执行区域中去拿的
-
从该空白Fragment 中获取 RequestManager
-
首次获取,则实例化 RequestManager
-
非空性检查:保证,宿主具有唯一RequestManager
- 对一个Activity或Fragment ,即使请求多次也只有一个 RequestManager
-
实例化:源码中搞了工厂模式,我们就简化掉
-
设置 Fragment 对应的 RequestManager 空白的Fragment<--->requestManager
-
-
返回RequestManager 对象
- 可以测试Glide.with() 的返回值,其实就是这个对象
-
-
设计思路:怎么拿到空白Fragment 的?分析:getSupportRequestManagerFragment
-
通过标记,从FragmentManager 中获取一次
- 标记:在源码中写的是作者的名字;那么我们自定义时,也可以这样写
-
上面没有获取到,那么会从保存集合中获取并提交
-
这里是设计了两个保存集合,分别存放androidx 的Fragment 与 app 的Fragment
-
实例化 Fragment
-
创建对象 空白的Fragment
-
【记录保存】映射关系 进行保存 第一个保障
-
提交 Fragment 事务
-
Handler ,post 一个消息,同时将保存记录集合中的信息给移除掉
- 因为RequestManagerRetriever 实现了Handler.Callback,用里面的handlerMessage 方法
-
-
-
为什么要去提交记录保存
-
不这样,就不能保证宿主、空白Fragment、RequestManager 一一对应
-
当创建好空白Fragment ,准备通过Fragment 的事务进行提交,因为Fragment 内部是Handler 机制,这时并不会马上提交进去(Handler 原理中可知),这时异步的,但用户发起了多个Glide 请求,那么就出现了多个空白Fragment ;
-
为了解决这个问题,那么就搞了一个保存记录的集合;同时使用Handler,post 一个消息,同时将保存记录集合中的信息给移除掉
- 因为RequestManagerRetriever 实现了Handler.Callback,用里面的handlerMessage 方法
-
-
还有其他细节:
-
Handler 中是通过标记来post 消息以及移除消息保存集合中的记录;
- 对两个集合都要处理
-
在RequestManagerRetriever 中实例化Handler 对象时,传入Looper.getMainLooper(),保证其是主线程中的东西
-
双重检测操作:保证宿主、空白Fragment、RequestManager 一一对应
-
使用保存记录集合,解决多个请求只有一个空白Fragment
-
将空白Fragment 的Message 从等待队列中发送到执行区域
-
发送Handler 让等待队列中的消息发送到工作区域
- 事务的本质是Handler,加入发起三个Glide 请求,那么就有三个Message
- 空白Fragment 还没有执行,发送一次Handler 将Message 从等待队列中发到执行区域中
- 如果空白Fragment 的Message 一直在等待队列中,那么下一次Glide 请求中;就会再来一个空白Fragment
- 在第二次查找时,就不会为Null ,这样就不会再去创建空白Fragment
-
-
-
绑定层:
-
写什么:接口 + 实现类
-
Lifecycle 接口
package com.derry.dlifecycle.glide.binding.inter; import androidx.annotation.NonNull; public interface Lifecycle { void addListener(@NonNull LifecycleListener listener); void removeListener(@NonNull LifecycleListener listener); }
-
LifecycleListener 接口
package com.derry.dlifecycle.glide.binding.inter; public interface LifecycleListener { void onStart(); void onStop(); void onDestroy(); }
-
ApplicationLIfecycle:子线程调用流程
-
为什么在addListener 中添加listener.onStart()?
- 因为此时是Application 作用域,当APP 启动后执行onStart();
- 因为子线程是没有空白Fragment 的,是无法监听的,那么我们就在APP 一启动我就启动
- 子线程中,在实例化 RequestManager的时候,会执行 this.lifecycle.addListener(this);
- 此时,由于是子线程,无法搞一个空白的Fragment覆盖上去,也意味着无法监听 Activity/Fragment
- 所以 只能是在addListener时,手动的onStart了
-
为什么里面什么都不干?
- 它也想干,但是没有空白Fragment 做基础,也就干不了;那么,直接设计成APP 灭亡其就灭亡
- 子线程中,由于无法搞一个空白的Fragment覆盖上去,也意味着无法监听 Activity/Fragment
- 那么只能是属于 全局大范围的跟随App进程的灭亡,而灭亡了,所以啥事也不干了...
-
源码展示
package com.derry.dlifecycle.glide.binding; import androidx.annotation.NonNull; import com.derry.dlifecycle.glide.binding.inter.Lifecycle; import com.derry.dlifecycle.glide.binding.inter.LifecycleListener; // Applicatoin作用域 子线程调用流程 public class ApplicationLifecycle implements Lifecycle { @Override public void addListener(@NonNull LifecycleListener listener) { listener.onStart(); } @Override public void removeListener(@NonNull LifecycleListener listener) { } }
-
-
ActivityFragmentLifecycle:主线程调用流程
-
设计思路
- 实现Lifecycle 接口、存在容器存放LifecycleListener,存在启动与终止标记
- 首次启动时,会调用onStop() 停止,然后再onStart()
- 在各个回调函数中,均会遍历容器,对其中元素执行相应回调操作,跳到RequestManager 中
-
完整代码:
package com.derry.dlifecycle.glide.binding; import androidx.annotation.NonNull; import com.derry.dlifecycle.glide.binding.inter.Lifecycle; import com.derry.dlifecycle.glide.binding.inter.LifecycleListener; import java.util.Collections; import java.util.Set; import java.util.WeakHashMap; // 非Applicatoin作用域 绿色色领域 只有他有资格 搞一个空白的Fragment来监听 public class ActivityFragmentLifecycle implements Lifecycle { // 容器,存放LifecycleListener private final Set<LifecycleListener> lifecycleListeners = Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>()); private boolean isStarted; // 启动的标记 private boolean isDestroyed; // 销毁的标记 @Override public void addListener(@NonNull LifecycleListener listener) { lifecycleListeners.add(listener); if (isDestroyed) { listener.onDestroy(); } else if (isStarted) { listener.onStart(); } else { listener.onStop(); // 首次启动:会默认 onStop 先停止 然后再onStart } } @Override public void removeListener(@NonNull LifecycleListener listener) { lifecycleListeners.remove(listener); } void onStart() { isStarted = true; for (LifecycleListener lifecycleListener : lifecycleListeners) { lifecycleListener.onStart(); } } void onStop() { isStarted = false; for (LifecycleListener lifecycleListener : lifecycleListeners) { lifecycleListener.onStop(); } } void onDestroy() { isDestroyed = true; for (LifecycleListener lifecycleListener : lifecycleListeners) { lifecycleListener.onDestroy(); } } }
-
-
SupportRequestManagerFragment:空白Fragment
-
设计思路:基础环境
- 必须继承androidX 的Fragment
- andridx 的 空白的Fragment 监听生命周期变化的
- 提供非Application 作用域的Fragment
-
设计思路:构造函数
- 无参构造中new 出提供非Application 作用域的Fragment
- 带参构造中,绑定提供非Application 作用域的Fragment
-
设计思路:get()/set()
- get():拿到Lifecycle 实现类ActivityFragmentLifecycle
- set():设置Lifecycle 实现类ActivityFragmentLifecycle
-
设计思路:onAttach() 与 onDetach()
- 重写父类即可
- 在RequestManager 构造中已经注册了,在Destroy 中已经移除了,所以简化掉
-
设计思路:onStart()、onStop()、onDestroy()
-
三个干事情的函数:当空白Fragment 触发回调时 ---> LifecycleListener回调 ---> RequestManager 回调
-
onStart():宿主可见性恢复
- 直接杀到RequestManager 回调
-
onStop():宿主可见性暂停
- 直接杀到RequestManager 回调
-
onDestroy():宿主被销毁
- 直接杀到RequestManager 回调
-
-
完整代码:
package com.derry.dlifecycle.glide.binding; import android.annotation.SuppressLint; import android.content.Context; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; //必须继承androidX 的Fragment import androidx.fragment.app.Fragment; import com.derry.dlifecycle.glide.RequestManager; // andrid x 的 空白的Fragment 监听生命周期变化的 public class SupportRequestManagerFragment extends Fragment { private static final String TAG = "SupportRMFragment"; //非Application 作用域的Fragment private final ActivityFragmentLifecycle lifecycle; @Nullable private RequestManager requestManager; //构造函数一 public SupportRequestManagerFragment() { this(new ActivityFragmentLifecycle()); } //构造函数二 @VisibleForTesting @SuppressLint("ValidFragment") public SupportRequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) { this.lifecycle = lifecycle; } //set() public void setRequestManager(@Nullable RequestManager requestManager) { this.requestManager = requestManager; } //get() @NonNull public ActivityFragmentLifecycle getGlideLifecycle() { return lifecycle; } @Nullable public RequestManager getRequestManager() { return requestManager; } //在RequestManager 构造中已经注册了,在Destroy 中已经移除了,所以简化掉onAttach() 与 onDetach() @Override public void onAttach(@NonNull Context context) { super.onAttach(context); // this.lifecycle.addListener(requestManager); } @Override public void onDetach() { super.onDetach(); } //三个干事情的函数:当空白Fragment 触发回调时 ---> LifecycleListener回调 ---> RequestManager 回调 @Override public void onStart() { super.onStart(); lifecycle.onStart();//直接杀到RequestManager 回调 } @Override public void onStop() { super.onStop(); lifecycle.onStop(); } @Override public void onDestroy() { super.onDestroy(); lifecycle.onDestroy(); } }
-
编写简化版本Glide 中的类:ImageViewTartget
-
ImageViewTartget:用于展示图片
-
编写业务逻辑:重写回调操作,在其中执行业务逻辑
-
怎么将ImageViewTartget 与 Glide 关联起来 ?
- 直接在RequestManager 中定义出这个控件;
- 直接在RequestManager 重写的回调函数中直接调用ImageViewTartget 相应的回调
编写简化版本Glide 中的类:TargetTracker
-
TargetTracker 作用:监听网络状态
- 根据宿主生命周期,当网络卡顿时,通过广播,弹出Toast
-
基础环境:
-
网络实体Bean:
- 定义响应码字段,标志位(表示成功 or 失败) + get()/set()
-
广播接收者:重写onReceive()
- 弹出Toast ,提示用户网络不给力
-
-
关键类:DefaultConnectivity (网络广播)
-
基础环境:
- 实现LifecycleListener 接口
- 成员变量:Context、前面定义的广播接收者
- 构造函数:对Context 赋值
-
重写回调函数:
-
onStart() :此时宿主可见,实例化广播接收者,将广播(当手机网络不好就能接收到)注册到Context 上
-
onStop() :此时宿主不可见,解除Context 上的广播的注册
- 界面不可见,那么就移除掉
-
onDestroy() :宿主被销毁掉了,那就销毁
-
-
-
怎么将关键类与RequestManager 关联起来 ?
-
在RequestManager 中:
-
实例化关键类对象,传入宿主对象
-
onStart() 中:this.ifecycle.addListener(关键类对象):
- 直接将这个关键类注册到ActivityFragmentListener中的set集合(存放的是LifecycleListener 对象)中
-
在onDestroy() 中:this.lifecycle.removeListener(关键类对象):
- 直接将这个关键类从ActivityFragmentListener中的set集合(存放的是LifecycleListener 对象)中,移除掉;
-
-
-
总结:Glide 源码中存在两种方式将自定义类与Glide 关联
- 第一种:直接在RequestManager 的回调中注册
- 第二种:直接将这个类对象,放入主线程流程中的ActivityFragmentLifecycle 中的 set 集合(存放LifecycleListener 对象)
- 可能是为了扩展吧
启动Glide
-
启动手写框架:
-
Glide 框架在首次启动时,会先停止掉;
- 打印onStop
-
紧接着由于宿主Activity 被启动
- 打印onStart,运行队列全部执行、等待队列全部清空
-
此时若退出宿主Activity
- 打印onStop,运行队列全部停止,将任务都加到等待队列
- 打印onDestroy,移除自身绑定的生命周期,释放操作
-
-
跟之前的开发方式的区别:
-
之前的,需要用户主动回调
- 在宿主声明周期回调中直接执行相关的逻辑
-
现在的,使用空白Fragment 进行监听,实现全自动化处理操作;
-
Glide 零散知识点
Glide 的影响力
- Jetpack 组件库,基本上是模仿Glide 框架;
- Glide 由私人开发,但被Google 选中,称为官方框架
Glide 中的类
-
ImageViewTarget:用于展示图片
- 业务场景:当服务器在请求图片时,宿主被干掉了(图片没有保存的位置了),那么Glide 会通知ImageViewTarget 终止其流程,结束更新,避免崩溃问题;
Glide 源码概览:into 流程
- 具有20 个类,保守估计有50 个小流程
问题概览:
-
为什么要去移除集合中的记录
- 虽然集合保证了,一一对应,但是我想让它马上执行
- 严谨
-
Glide 版本差异
- 3.1 的时候,为什么要发送一次空的Handler,其实就是为了让它立即执行
- 后续的版本加入了许多的设计模式等等细节
-
Fragment 与 Activity 是在哪里绑定的?
-
在RequestManager 的构造函数中就绑定了
public class RequestManager implements LifecycleListener { private Lifecycle lifecycle; public RequestManager(Glide glide, Lifecycle lifecycle, Context applicationContext) { this.lifecycle = lifecycle; this.lifecycle.addListener(this); // 构造函数 已经给自己注册了【自己给自己绑定】 } …… @Override public void onDestroy() { Log.d(LOG.TAG, "onDestroy: 自己负责移除自己绑定的生命周期监听,释放操作 ...."); // 已经给自己销毁了 【自己给自己移除】 this.lifecycle.removeListener(this); } }
-
-
Glide 源码的流程是什么样的?
-
Glide.with(FragmenActivity)
-
RequestManager.get(FragmenActivity)
- 如果是子线程,属于Application 作用域
- 如果是主线程,属于非Application 作用域,搞一个空白Fragment
-
Application 作用域
-
实例化ApplicationLifecycle (实现Lifecycle 接口)
- 其中什么都不干的,因为没有空白Fragment 是无法监听也无法移除,那么就随APP 的灭亡而灭亡
-
-
非Application 作用域
-
调用RequestManager 的管理类 RequestManagerRetriver ,获得RequestManager 对象
- 通过参数(宿主Activity),获取FragmentManager ,将其作为参数向下传递给获取空白Fragment 的supportRequestManagerFragment
-
获取空白Fragment ,将其绑定并返回
- 里面存在核心函数getSupportRequestManagerFragment ,保证宿主、空白Fragment、RequestManager 对应且均只有一个 ;由双重保障进行实现(fragment 提交记录集合 + Handler)
-
-
-
为什么在Fragment 事务提交时,要使用commitAllowingStateLoss(),而不直接使用commit ?
- commit 会抛出异常
-
Glide 有什么功能亮点 ?
- 支持GIF 、视频第一帧等
-
Glide 监听哪些函数 ?
- onStart()、onStop()、onDestroy()
-
容器里面存的是什么?
-
两个空白Fragment,一个androidx 的 一个app 的;
-
其实,不只是这些,因为后续考虑到功能扩展
-