Glide 系列三:如何手写一个Glide 框架?

762 阅读12分钟

Glide 系列三:如何手写一个Glide 框架?

本文概述:

  • 本文介绍了简易Glide 框架的搭建流程,但因Glide 框架过于复杂;做了大量简化,砍掉了部分代码;在文章末尾简单介绍了关于Glide 的一些零散问题;

手写基础:

  • 需要深入理解Glide 整体架构,并清楚源码走向

image-20220817181510107

  • 手写时,去掉不必须的东西,在源码的基础上进行修改;

整体工程架构:

image-20220817181551531

工具层:

  • 来源自源码,代码过多,不便展开,如有需要请联系我

image-20220817181811857

环境层:

  • 有什么?

    image-20220817181912226

  • 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)

      1. 从 FragmentManager 中获取 SupportRequestManagerFragment(空白) ,注意是从执行区域中去拿的

      2. 从该空白Fragment 中获取 RequestManager

      3. 首次获取,则实例化 RequestManager

        • 非空性检查:保证,宿主具有唯一RequestManager

          • 对一个Activity或Fragment ,即使请求多次也只有一个 RequestManager
        • 实例化:源码中搞了工厂模式,我们就简化掉

        • 设置 Fragment 对应的 RequestManager 空白的Fragment<--->requestManager

      4. 返回RequestManager 对象

        • 可以测试Glide.with() 的返回值,其实就是这个对象
    • 设计思路:怎么拿到空白Fragment 的?分析:getSupportRequestManagerFragment

      1. 通过标记,从FragmentManager 中获取一次

        • 标记:在源码中写的是作者的名字;那么我们自定义时,也可以这样写
      2. 上面没有获取到,那么会从保存集合中获取并提交

        • 这里是设计了两个保存集合,分别存放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

绑定层:

  • 写什么:接口 + 实现类

    image-20220817182149422

  • 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 的;

    • 其实,不只是这些,因为后续考虑到功能扩展