不敢说懂你 - Glide硬核源码剖析

问题

Glide加载流程?

Glide整体架构?

Glide数据加载的来源?

Glide缓存加载的流程?

Glide线程切换原理?

Glide如何感知Activity?

Glide哪种情况会返回应用级的RequestManager?

带着一些问题去阅读…

使用示例

本篇主要基于glide:4.12.0进行分析。下面是Glide主要的使用示例。

repositories {
  google()
  mavenCentral()
}

dependencies {
  implementation 'com.github.bumptech.glide:glide:4.12.0'
  annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
}

 Glide.with(this).load("http://goo.gl/gEgYUd").into(imageView);

可以看到,Glide的加载主要分三步:with()load()into()。理解了这三步Glide做了什么,基本就理解了Glide源码加载图片的大体逻辑和框架了。

with()

Glide的with()方法的目的是根据不同的上下文context获得RequestManager对象。

RequestManager对象解释:A class for managing and starting requests for Glide.

下面开始详细分析。

首先看Glide中with()方法所有的重载函数:

RequestManager with(Context context)
RequestManager with(android.app.Activity)
RequestManager with(androidx.fragment.app.Fragment)
RequestManager with(androidx.fragment.app.FragmentActivity)
RequestManager with(View view)

以Glide中的 with(android.app.Activity)为例:

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

可以看到,RequestManagergetRetriever(activity).get(activity)得到,因此有两个问题:

1 getRetriever(activity)获得什么对象?

2 这个对象的get()获得什么?

首先看第一个问题,看getRetriever(activity):

private static RequestManagerRetriever getRetriever(@Nullable Context context) {
   
    ...
    return Glide.get(context).getRequestManagerRetriever();
  }

getRetriever(activity)获得了RequestManagerRetriever对象。

接下来进RequestManagerRetriever对象看它的get()实现,它根据with()重载方法参数的不同进行不同重载:

RequestManager get(Context context)
RequestManager get(android.app.Activity)
RequestManager get(androidx.fragment.app.Fragment)
RequestManager get(androidx.fragment.app.FragmentActivity)
RequestManager get(View view)

以其中一个为例:

  public RequestManager get(@NonNull FragmentActivity activity) {
   
    if (Util.isOnBackgroundThread()) {
   
      return get(activity.getApplicationContext());
    } else {
   
      assertNotDestroyed(activity);
      frameWaiter.registerSelf(activity);
      FragmentManager fm = activity.getSupportFragmentManager();
      return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }

可以看到,RequestManager返回两种类型,分别是当是子线程时的get(activity.getApplicationContext());和其他的supportFragmentGet()

首先看with()在子线程中统一返回的应用级别RequestManager单例,看 get(activity.getApplicationContext());

 @NonNull
  public RequestManager get(@NonNull Context context) {
   
    ...
       if (context instanceof FragmentActivity) {
   
        return get((FragmentActivity) context);
    ...
  }

继续追这个get()方法的具体实现:

  public RequestManager get(@NonNull Context context) {
   
    if (context == null) {
   
      throw new IllegalArgumentException("You cannot start a load on a null Context");
    } else if (Util.isOnMainThread() && !(context instanceof Application)) {
   
      if (context instanceof FragmentActivity) {
   
        return get((FragmentActivity) context);
      } else if (context instanceof Activity) {
   
        return get((Activity) context);
      } else if (context instanceof ContextWrapper
          && ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
   
        return get(((ContextWrapper) context).getBaseContext());
      }
    }
    return getApplicationManager(context);
  }

看到这一行:if (Util.isOnMainThread() && !(context instanceof Application)),这行判断不仅决定了子线程中直接返回getApplicationManager(context)方法,而且当这个传入的context是Application时,也返回全局的getApplicationManager(context)方法获得的应用级别RequestManager

继续追这个getApplicationManager(context)方法的具体实现:

 @NonNull
  private RequestManager getApplicationManager(@NonNull Context context) {
   
    if (applicationManager == null) {
   
      synchronized (this) {
   
        if (applicationManager == null) {
   
          Glide glide = Glide.get(context.getApplicationContext());
          applicationManager =factory.build(...);
        }
      }
    }
    return applicationManager;
  }

至此我们知道了with()返回是应用级别RequestManager单例:applicationManager的两种情况:子线程+context=Application

那么不是子线程时的supportFragmentGet()呢,这种情况又是如何生成的RequestManager?我们具体看下RequestManagerRetriever.supportFragmentGet()

 private RequestManager supportFragmentGet(@NonNull Context context,@NonNull FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
   
   
    //获取空fragment,无则创建
    SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);
    
   // 让fragment持有RequestManager
   RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
   
      //如果空fragment没有RequestManager,就创建一个
      Glide glide = Glide.get(context);
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      ...
      //让空fragment持有RequestManager
      current.setRequestManager(requestManager);
    }
   
   //返回页面级别的RequestManager
    return requestManager;
  }

继续看这个新fragment怎么创建的:

private SupportRequestManagerFragment getSupportRequestManagerFragment(
    @NonNull final FragmentManager fm, @Nullable Fragment parentHint) {
   
   //通过tag找到Activity中的空fragment
  SupportRequestManagerFragment current =
      (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
  if (current == null) {
   
     //findFragmentByTag没找到空fragment,有可能是延迟问题?再从Map中找一下
    current = pendingSupportRequestManagerFragments.get(fm);
    if (current == null) {
   
       //确实没有空fragment,就创建一个
      current = new SupportRequestManagerFragment();
      current.setParentFragmentHint(parentHint);
      //缓存进Map
      pendingSupportRequestManagerFragments.put(fm, current);
      //空fragment添加到Activity,使其能感知Activity的生命周期
      fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
      handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
    }
  }
  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/560912.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode 11.盛最多谁的容器

目录 题目描述 方法一 双指针 思路: 代码: 题目描述 给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的…

实验室三大常用仪器1---示波器的基本使用方法(笔记)

目录 示波器的作用 示波器的基础操作方法 示波器测量突变脉冲 示波器的作用 示波器能帮助我们干什么? 比如说某个电源用万用表测量是稳定的5V输出 但是用示波器一看确实波涛汹涌 这样的电源很可能回导致系统异常工作 又比如电脑和单片机进行串口通信时&#xf…

ubuntu在xshell中使用快捷方式操作命令,减少命令行的数入量

第一步 第二步 然后无脑确定 第三步 在xshell的显示方式 方式一 这样就会在每个窗格中进行显示 方式二 效果显示–> 这种窗格的显示是全局的 然后你双击这个process就会自动把命令打在命令行上,减少你的输入量

如何在本地服务器部署TeslaMate

文章目录 1.主要参考官方文档2.准备文件:docker-compose.yml3.运行4.成功后4.1 在这个链接,更具提示登录4.2 在这个链接可以看到电池健康和行车数据等 5.后续说明6.进行数据备份6.1 先将数据进行备份,参考链接6.2 数据迁移6.3 下图为我挂该数…

布隆过滤器初探

1、什么是布隆过滤器 布隆过滤器是一个很长的二进制向量和一系列随机hash函数。布隆过滤器可以用于检索一个元素是否在一个集合中。 常见的hash函数的应用hashMap、hashSet等 回顾一下hashMap的结构 hashMap由数组链表红黑树(java1.8后,链表元素长度大…

七月论文审稿GPT第4.5版:通过15K条paper-review数据微调Llama2 70B(含各种坑)

前言 当我们3月下旬微调完Mixtral 8x7B之后(更多详见:七月论文大模型:含论文的审稿、阅读、写作、修订 ),下一个想微调的就是llama2 70B 因为之前积攒了不少微调代码和微调经验,所以3月底apple便通过5K的paper-review数据集成功…

xilinx cpri ip 开发记录

CPRI是无线通信里的一个标准协议,连接REC和RE的通信。 Xilinx有提供CPRI IP核。 区别于其它通信协议,如以太网等,CPRI是一个同步系统。 这就意味着两端的Master和Slave应当是同源时钟的,两边不存在频差,并且内部延时…

使用isort和autopep8统一代码风格

前言 今天和大家分享一篇关于python代码风格统一的方法。我自己之前有使用过,但都是使用公司现成的,没有自己动手去实操,所以为了一探究竟,今天专门花了一点时间去研究,这个过程还挺顺利的,这里我将这个过…

什么是IIoT?

什么是IIoT? IIoT,即工业物联网(Industrial Internet of Things),是指将物联网技术应用到工业领域,通过微型低成本传感器、高带宽无线网络等技术手段,实现工业设备、系统和服务的互联互通,从而提高生产效率、降低能耗和成本,实现智能化和自动化生产。 IIoT的应用范围…

Vitis HLS 学习笔记--BLAS库之WideType

目录 1. WideType 数据类型 2. WideType 类模板参数 2.1 SFINAE技术 3. WideType 类中的函数 3.1 operator[](unsigned int p_Idx) 3.2 operator(const WideType& p_w) const 3.3 getValAddr() 3.4 operator const t_TypeInt() 4. 总结 1. WideType 数据类型 在 …

NtripShare2024年第一季度主要技术进展

迷迷糊糊又是一个月没有写点什么,近期想清楚NtripShare在2024的要做什么事情,暂且将NtripShare要做的主要事情为搭建由软件与硬件之间的技术桥梁。 在过去的几年时间里NtripShare对硬件方面一直是规避的态度,今年开始要做一点软硬件搭界的技…

网络编程初步

协议: 一组规则 分层模型结构: OSI七层模型:物、数、网、传、会、表、应 TCP/IP 4层模型:网(链路层/网络接口层)、网、传、应 应用层:http、 ftp、 nfs、 ssh、 telneto o .传输层:TCP、UDP 网络层&…

SpringBoot基于JavaWeb的菜鸟驿站快递管理系统ssm

前端:vue.jsElementUI 编程语言: java 框架: ssm/springboot 详细技术:springboot springbootvueMYSQLMAVEN 数据库: mysql5.7 数据库工具:Navicat/SQLyog都可以 ide工具:IDEA 或者eclipse 对菜鸟驿站快递管理系统设计…

判别饮用水可饮用的多机器学习模型

注意:本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 ([www.aideeplearning.cn]) 项目背景 饮用水是人类生存的基本需求之一,也是维护健康和有效保护健康政策的重要组成部分。因此,确保饮用水质量对于国…

3分钟看懂Microchip 32位MCU CAN模块的配置

文章目录 CAN模块系统框图Microchip MCC Harmony下CAN模块配置选项CAN模块工作模式CAN模块中断模式CAN工作速率Bit Timing Calculation配置CAN 接收的配置CAN 发送的配置CAN 过滤器工作流程说明CAN 过滤器的配置 CAN模块系统框图 CAN的英文全称:Control Area Networ…

通过linux工具iftop命令查看视频监控平台是否收到监控摄像头的视频流(视频监控平台接收和转发的视频流)

目录 一、需求描述 二、解决思路 (一)问题分析 (二)解决思路 1、通过抓包的方式 2、通过一些linux的网络监视工具 三、需求实现 (一)抓包工具 1、tcpdump 2、Wireshark 3、tcptrace &#xff0…

OpenHarmony 网络与连接—RPC连接

介绍 本示例使用ohos.rpc 相关接口,实现了一个前台选择商品和数目,后台计算总价的功能,使用rpc进行前台和后台的通信。 效果预览 使用说明: 点击商品种类的空白方框,弹出商品选择列表,选择点击对应的商品…

天软因子数据系列课堂回顾——“委托订单:流动性因子”

高频因子库4月更新,新增5张表单,51个因子。目前,高频因子数量扩容到628个,涵盖了从2000年开始的全A市场。本次“天软因子数据系列课堂”在线分享的即是最新发布因子列表之一的流动性因子,剖析微观角度下因子的底层逻辑…

什么是代理IP?如何正确使用代理IP?

代理IP(Proxy IP)是一种网络技术,它允许用户通过一个中介服务器(即代理服务器)来访问互联网。具体来说,代理IP隐藏了用户的真实IP地址,使用第三方的IP地址进行网络访问。当用户发起网络请求时&a…

Linux进阶篇:Centos7搭建smb服务

Centos7搭建smb服务 1 smb介绍 Samba是在Linux和UNIX系统上实现SMB协议的一个免费软件,由服务器及客户端程序构成。SMB(Server Messages Block,信息服务块)是一种在局域网上共享文件和打印机的一种通信协议,它为局域…