Android Retrofit原理浅析

news2025/1/19 3:40:28

retrofit

官方地址:Retrofit

原理:Retrofit 本质上是代理了OKhttp,使用代理模式,Type-Safe 类型安全 编译器把类型检查出 避免类型错误,

enqueue 异步 切换线程 

execute 同步 不切换线程 

enqueue:Call接口定义的抽象方法

Retrofit.Create() 方法首先验证接口validateServiceInterface(Class <T> service) 

  public <T> T create(final Class<T> service) {
//验证接口
    validateServiceInterface(service);

//动态代理 运行时创建
//getClassLoader classLoad 临时的ClassLoad
//new Class<?>[] { service } service 当前的interface 
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
 //实际代理匿名对象
 new InvocationHandler() {
          private final Platform platform = Platform.get();
          private final Object[] emptyArgs = new Object[0];

//核心方法  invoke 
          @Override public @Nullable Object invoke(Object proxy, Method method,
              @Nullable Object[] args) throws Throwable {
            // If the method is a method from Object then defer to normal invocation.

//确保是声明在接口里的方法(当前service  interface )而不是Object里的 如果是Object的方法 比如 toString  就调用这一行
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
//如果是JAVA8的默认方法 就执行
//platform 兼容类 可以兼容一些旧平台做默认处理 
// 比如platform 里的 isDefaultMethod 方法 会判断java8 hasJava8Types
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }

//通过loadMethod方法进行反射调用
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }

ServiceMethod<?> loadServiceMethod(Method method) {
//从缓存中读取
//serviceMethodCache 是一个Map ,用Map做缓存
    ServiceMethod<?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
//核心方法
        result = ServiceMethod.parseAnnotations(this, method);
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

HttpServiceMethod

 @Override final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }


 Type adapterType;
    if (isKotlinSuspendFunction) {
      Type[] parameterTypes = method.getGenericParameterTypes();
      Type responseType = Utils.getParameterLowerBound(0,
          (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
      if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
        // Unwrap the actual body type from Response<T>.
        responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
        continuationWantsResponse = true;
      } else {
        // TODO figure out if type is nullable or not
        // Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class)
        // Find the entry for method
        // Determine if return type is nullable or not
      }

      adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
      annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
    } else {
      adapterType = method.getGenericReturnType();
    }

 okhttp3.Call.Factory callFactory = retrofit.callFactory;

//是否是kotlin挂起 的方法所生成的  关键字 susped
    if (!isKotlinSuspendFunction) {
      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    } else if (continuationWantsResponse) {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForResponse<>(requestFactory,
          callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
    } else {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForBody<>(requestFactory,
          callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
          continuationBodyNullable);
    }


OkhttpCall 
OkHttpCall<T> implements Call<T>

  @Override public void enqueue(final Callback<T> callback) {
//空值判断
    Objects.requireNonNull(callback, "callback == null");

    okhttp3.Call call; //call  
//    okhttp3.Call call = callFactory.newCall(requestFactory.create(args)); 通过工厂模式创建

    Throwable failure;

    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;

      call = rawCall;
      failure = creationFailure;
      if (call == null && failure == null) {
        try {
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          throwIfFatal(t);
          failure = creationFailure = t;
        }
      }
    }

    if (failure != null) {
      callback.onFailure(this, failure);
      return;
    }

    if (canceled) {
      call.cancel();
    }

//okhttp enqueue 执行
    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
        Response<T> response;
        try {
//解析数据 
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          throwIfFatal(e);
          callFailure(e);
          return;
        }

        try {
//解析成功
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          throwIfFatal(t);
          t.printStackTrace(); // TODO this is not great
        }
      }

      @Override public void onFailure(okhttp3.Call call, IOException e) {
//解析失败
        callFailure(e);
      }

      private void callFailure(Throwable e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          throwIfFatal(t);
          t.printStackTrace(); // TODO this is not great
        }
      }
    });
  }

一系列验证

private void validateServiceInterface(Class<?> service) {
    if (!service.isInterface()) {
//验证是不是传入的一个Interface 不是的话就抛异常
      throw new IllegalArgumentException("API declarations must be interfaces.");
    }

//创建一个双向队列 
    Deque<Class<?>> check = new ArrayDeque<>(1);
//添加当前service 
    check.add(service);
    while (!check.isEmpty()) {
//移除上一个添加的  然后读取后面的
      Class<?> candidate = check.removeFirst();

      if (candidate.getTypeParameters().length != 0) {
//判断不能是泛型接口  <T>   是泛型接口 抛出异常
        StringBuilder message = new StringBuilder("Type parameters are unsupported on ")
            .append(candidate.getName());
        if (candidate != service) {
          message.append(" which is an interface of ")
              .append(service.getName());
        }
        throw new IllegalArgumentException(message.toString());
      }
      Collections.addAll(check, candidate.getInterfaces());
    }

//进一步验证  validateEagerly 验证flag
    if (validateEagerly) {
      Platform platform = Platform.get();
      for (Method method : service.getDeclaredMethods()) {
//判断是否是默认方法和静态方法 
//防止java8有默认实现方法和静态的方法
        if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {

//Retrofit 接口第一次被调用的时候 会有一些初始化操作 包括验证
          loadServiceMethod(method);
        }
      }
    }
  }


 ServiceMethod<?> loadServiceMethod(Method method) {
    ServiceMethod<?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = ServiceMethod.parseAnnotations(this, method);
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

adapt 包装盒适配了OkHttpCall 异步切换线程以及适配RxJava, 

通过包装CallAdapter,内部通过CallBackExecutor实现

然后由Executor 线程池 的CallBack进行同步操作 execute

通过ExecutorCallBackCall 置换OkHttpCall 

会涉及到PlatForm的DefaultCallBackExecutor 创建MainThreadExecutor 然后执行Runable

OkHttpCall 创建过程

RequestFactory.parseAnnotions 通过Build, 通过parseMethodAnnotions 分析注解  枚举 比如GET / POST /DELETE / PUT等 对请求方法进行记录 分析 以及注解 参数类型 和 返回类型 进行判断进行拼接 然后通过ReequestFastory创建OkHttp3的Request

解析结果 parseRespose,通过ReseponseConverter.convert对数据 进行解析,在OKHTTPCall创建的时候创建出来

GsonCOnverterFastory 解析 通过conver方法 然后通过JsonReader

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ps吸管工具用不了怎么办?

我们的办公神器ps软件&#xff0c;大家一定是耳熟能详的吧。Adobe photoshop是电影、视频和多媒体领域的专业人士&#xff0c;使用3D和动画的图形和Web设计人员&#xff0c;以及工程和科学领域的专业人士的理想选择。Photoshop支持宽屏显示器的新式版面、集20多个窗口于一身的d…

小数据 vs 大数据:为AI另辟蹊径的可操作数据

在人工智能背景下&#xff0c;您可能已听说过“大数据”这一流行语&#xff0c;那“小数据”这一词呢&#xff0c;您有听说过吗&#xff1f;无论您听过与否&#xff0c;小数据都无处不在&#xff1a;线上购物体验、航空公司推荐、天气预报等均依托小数据。小数据即一种采用可访…

webpack 和 ts 简单配置及使用

如何使用webpack 与 ts结合使用 新建项目 &#xff0c;执行项目初始化 npm init -y会生成 {"name": "tsdemo01","version": "1.0.0","description": "","main": "index.js","scripts&…

java_免费文本翻译API_小牛翻译

目录 前言 开始集成API 纯文本翻译接口 双语对照翻译接口 指定术语翻译接口 总结 前言 网络上对百度&#xff0c;有道等的文本翻译API集成的文章比较多&#xff0c;所以集成的第一篇选择了小牛翻译的文本翻译API。 小牛翻译文本翻译API&#xff0c;支持388个语种&#xff0…

CrossOver2023快速在Mac和Linux系统上运行Windows软件

让您可以在 Mac 和 Linux 系统上运行 Windows 应用&#xff0c;不必购买 Windows 授权&#xff0c;不必重启系统&#xff0c;不必使用虚拟机。通过 CrossOver&#xff0c; 您可以从 dock 直接启动 Windows 应用&#xff0c;与您的 Mac 和 Linux 系统功能无缝集成。 无需重启 Cr…

强训第35天

选择 A 经过一个1->2 经过两个2->4 开始慢增长 4->5 5->6....9->10 到达4KB时变成慢增长&#xff0c;最多增长到10 D 网络号是180.80.76 但题目让向主机所在子网发广播 180 .80 .(01001101 | 111111 11)79 .255 标红的两位属于主机号所以答案为D A C 分片的组…

排名算法简介:对搜索结果进行排序的主要排名算法

一、介绍 学习排名 &#xff08;LTR&#xff09; 是一类监督式机器学习算法&#xff0c;旨在根据项目与查询的相关性对项目列表进行排序。在分类和回归等问题中的经典机器学习中&#xff0c;目标是根据特征向量预测单个值。LTR 算法对一组特征向量进行操作&#xff0c;并预测项…

【FAQ】视频集中存储EasyCVR安防监控平台接入AI分析时的通道显示问题排查

安防视频监控平台视频集中存储EasyCVR可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。 安防监控视频云存储平台EasyCVR既具…

为什么贴片电阻的阻值不规律?为了在某精度下做到阻值的全覆盖(对,但不全对),E系列电阻的算法(E12系列值不对的猜想)

1、先放上E系列的电阻表格 E12精度10%&#xff0c;E24精度5%&#xff0c;E96精度1%&#xff1b; 2、以精度作为条件的演算 通常我们选择电阻&#xff0c;要确定电阻的精度&#xff0c;如果以精度作为条件。 以10%精度来说&#xff1a;&#xff08;数值少&#xff0c;好算&am…

STM32 CubeMX (第二步Freertos任务通信:队列、信号量、互斥量,事件组,任务通知)

STM32 CubeMX STM32 CubeMX ____Freertos任务通信&#xff1a;队列、信号量、互斥量&#xff0c;事件组&#xff0c;任务通知 STM32 CubeMX一、STM32 CubeMX设置时钟配置HAL时基选择TIM1&#xff08;不要选择滴答定时器&#xff1b;滴答定时器留给OS系统做时基&#xff09;使用…

超分辨率地震速度模型

文献分享 1. Multitask Learning for Super-Resolution 原题目&#xff1a;Multitask Learning for Super-Resolution of Seismic Velocity Model 全波形反演&#xff08;FWI&#xff09;是估算地下速度模型的强大工具。与传统反演策略相比&#xff0c;FWI充分利用了地震波的…

计算机丢失msvcp110.dll是什么意思?如何修复?

在日常使用电脑的时候&#xff0c;有时候会遇到一些使用问题。 比如&#xff0c;有一次遇到了这样一个问题。 那就是&#xff0c;因为“msvcp110.dll”这个文件丢失&#xff0c;有些软件安装不了。 计算机丢失msvcp110.dll是什么意思&#xff1f;该如何修复呢&#xff1f; ​…

05-微信小程序常用组件-表单组件

05-微信小程序常用组件-表单组件 文章目录 表单组件button 按钮案例代码 form 表单案例代码 image 图片支持长按识别的码案例代码 微信小程序包含了六大组件&#xff1a; 视图容器、 基础内容、 导航、 表单、 互动和 导航。这些组件可以通过WXML和WXSS进行布局和样式设…

LC-二叉树最大深度

LC-二叉树最大深度 链接&#xff1a;https://leetcode.cn/problems/maximum-depth-of-binary-tree/description/ 描述&#xff1a; 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 例1&#xff1a; …

一力破万法,Fiddler跟Charles抓包图文详解教程

一、Fiddler 1.1 Fiddler抓取HTTPS设置 1.1.1 配置证书 Tools菜单 —> Options —> HTTPS —> 勾选Decrypt HTTPS traffic选项。 说明&#xff1a; 勾选Decrypt HTTPS traffic选项&#xff1a;Decrypt HTTPS traffic&#xff1a;意思是解密HTTPS流量&#xff08;…

[VS/C++]如何更好的配置DLL项目中的成品输出

注意&#xff0c;解决方案与项目不放在同一个文件夹中&#xff0c;即不选中图中选项 直入主题 首先右键项目选择属性&#xff0c;或者选中项目然后AltEnter 选择配置属性下的常规 分别在四种配置中编辑输出目录如下 注意&#xff0c;四种配置要分别配置&#xff0c;一个个来…

leetcode做题笔记86分隔链表

给你一个链表的头节点 head 和一个特定值 x &#xff0c;请你对链表进行分隔&#xff0c;使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。 你应当 保留 两个分区中每个节点的初始相对位置。 示例 1&#xff1a; 输入&#xff1a;head [1,4,3,2,5,2], x 3 输出&am…

用pytorch实现google net

GoogleNet&#xff08;也称为Inception v1&#xff09;是由Google在2014年提出的一个深度卷积神经网络架构。它在ImageNet Large Scale Visual Recognition Challenge (ILSVRC) 2014比赛中取得了优秀的成绩&#xff0c;并引起了广泛的关注。 GoogleNet的设计目标是构建一个更…

【学会动态规划】最长湍流子数组(23)

目录 动态规划怎么学&#xff1f; 1. 题目解析 2. 算法原理 1. 状态表示 2. 状态转移方程 3. 初始化 4. 填表顺序 5. 返回值 3. 代码编写 写在最后&#xff1a; 动态规划怎么学&#xff1f; 学习一个算法没有捷径&#xff0c;更何况是学习动态规划&#xff0c; 跟我…

LeetCode49.字母异味词分组

我一开始的思路就是用1个hashmap<Integer,List<String>>,Integer存的的是字符串所有字母ASCLL值的和&#xff0c;List里面放异位字符串&#xff0c;但是不是异位的字符串的ascll值也可能相同比如acd和abe&#xff0c;所以这个hashmap只能降低一点时间复杂度我还是要…