Android Retrofit原理浅析

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

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

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

相关文章

RGOS日常管理操作

RGOS日常管理操作 一、前言二、RGOS平台概述2.1、锐捷设备的常用登陆方式2.2、使用Console登入2.3、Telnet远程管理2.4、SSH远程管理2.5、登陆软件&#xff1a;SecureCRT 三、CLI命令行操作3.1、CLI命令行基础3.2、CLI模式3.3、CLI模式互换3.4、命令行特性3.4.1、分屏显示3.4.2…

0基础入门C++之类和对象上篇

目录 1.面向过程和面向对象初步认识2.类的引入3.类的定义3.1类的两种定义方式:3.2成员变量命名规则的建议 4.类的访问限定符及封装4.1访问限定符4.2封装 5.类的作用域6.类的实例化7.类对象模型7.1如何计算类对象的大小7.2 类对象的存储方式猜测 8.this指针8.1this指针的引出8.2…

通过请求头传数据向后端发请求

axios &#xff08;get post请求、头部参数添加&#xff09;傻瓜式入门axios_axiospost请求参数_web_blog的博客-CSDN博客

http库 之 OKHttpUtil

源码位置 方便实用&#xff0c;个人感觉不错 依赖 <dependency><groupId>io.github.admin4j</groupId><artifactId>common-http-starter</artifactId><version>0.7.5</version> </dependency>代码实践 /*** 通用http的pos…

在 IDEA 中使用 Git开发 图文教程

在 IDEA 中使用 Git开发 图文教程 一、连接远程仓库二、IDEA利用Git进行开发操作三、分支操作3.1 新建分支3.2 切换分支3.3 删除分支3.4 比较分支3.5 合并分支 四、常用快捷键 一、连接远程仓库 一、打开IDEA&#xff0c;进入目录&#xff1a;File ->New ->Project from…

CSS和AJAX阶段学习记录

1、AJAX的工作原理&#xff1a; 如图所示&#xff0c;工作原理可以分为以下几步&#xff1a; 网页中发生一个事件&#xff08;页面加载、按钮点击&#xff09; 由 JavaScript 创建 XMLHttpRequest 对象 XMLHttpRequest 对象向 web 服务器发送请求 服务器处理该请求 服务器将响应…

C++项目实战之演讲比赛流程管理系统

演讲比赛流程管理系统 1. 演讲比赛程序需求 1.1 比赛规则 学校举行一场演讲比赛&#xff0c;共有12个人参加。比赛共两轮&#xff0c;第一轮为淘汰赛&#xff0c;第二轮为决赛 每名选手都有对应的编号&#xff0c;如 10001 ~ 10012 比赛方式&#xff1a;分组比赛&#xff0…

C语言之指针进阶篇(1)

目录​​​​​​​ 引言 字符指针 指针数组 数组指针 数组指针的定义 &数组名vs数组名 数组指针的使用 一维数组使用 二维数组使用 一维数组传参 二维数组传参 总结 数组参数 一维数组传参 二维数组传参 指针参数 一级指针传参 二级指针传参 引言 今…

【爬虫练习之glidedsky】爬虫-基础1

题目 链接 爬虫的目标很简单&#xff0c;就是拿到想要的数据。 这里有一个网站&#xff0c;里面有一些数字。把这些数字的总和&#xff0c;输入到答案框里面&#xff0c;即可通过本关。 思路 找到调用接口 分析response 代码实现 import re import requestsurl http://www.…

设计模式——桥接模式

引用 桥我们大家都熟悉&#xff0c;顾名思义就是用来将河的两岸联系起来的。而此处的桥是用来将两个独立的结构联系起来&#xff0c;而这两个被联系起来的结构可以独立的变化&#xff0c;所有其他的理解只要建立在这个层面上就会比较容易。 基本介绍 桥接模式&#xff08;Br…

【数据结构与算法】普里姆算法

普里姆算法 最小生成树 最小生成树&#xff0c;简称MST。 给定一个带权的无向连通图&#xff0c;如何选取一棵生成树&#xff0c;使树上所有边上权的总和为最小&#xff0c;这就叫最小生成树。N 个顶点&#xff0c;一定有 N - 1 条边半酣全部顶点N - 1 条边都在图中举例说明…

CAS 一些隐藏的知识,您了解吗

目录 ConcurrentHashMap 一定是线程安全的吗 CAS 机制的注意事项 使用java 并行流 &#xff0c;您要留意了 ConcurrentHashMap 在JDK1.8中ConcurrentHashMap 内部使用的是数组加链表加红黑树的结构&#xff0c;通过CASvolatile或synchronized的方式来保证线程安全的,这些原理…

Ubuntu 20.04(服务器版)安装 Anaconda

0、Anaconda介绍 Anaconda是一个开源的Python发行版本&#xff0c;包含了包括Python、Conda、科学计算库等180多个科学包及其依赖项。因此&#xff0c;安装了Anaconda就不用再单独安装CUDA、Python等。 CUDA&#xff0c;在进行深度学习的时候&#xff0c;需要用到GPU&#xf…

Lnton羚通算法算力云平台在环境配置时 OpenCV 无法显示图像是什么原因?

问题&#xff1a; cv2.imshow 显示图像时报错&#xff0c;无法显示图像 0%| | 0/1 [00:00<…

【java】为什么文件上传要转成Base64?

文章目录 1 前言2 multipart/form-data上传3 Base64上传3.1 Base64编码原理3.2 Base64编码的作用 4 总结 1 前言 最近在开发中遇到文件上传采用Base64的方式上传&#xff0c;记得以前刚开始学http上传文件的时候&#xff0c;都是通过content-type为multipart/form-data方式直接…

易服客工作室:Houzez主题 - 超级房地产WordPress主题/网站

Houzez主题是全球流行的房地产经纪人和公司的WordPress主题。 Houzez Theme是专业设计师创造一流设计的超级灵活起点。它具有您的客户&#xff08;房地产经纪人或公司&#xff09;甚至可能做梦也想不到的功能。 网址&#xff1a;Houzez主题 - 超级房地产WordPress主题/网站 - …

Java请求Http接口-hutool的HttpUtil(超详细-附带工具类)

概述 HttpUtil是应对简单场景下Http请求的工具类封装&#xff0c;此工具封装了HttpRequest对象常用操作&#xff0c;可以保证在一个方法之内完成Http请求。 此模块基于JDK的HttpUrlConnection封装完成&#xff0c;完整支持https、代理和文件上传。 导包 <dependency>&…

[保研/考研机试] KY96 Fibonacci 上海交通大学复试上机题 C++实现

题目链接&#xff1a; KY96 Fibonacci https://www.nowcoder.com/share/jump/437195121692000803047 描述 The Fibonacci Numbers{0,1,1,2,3,5,8,13,21,34,55...} are defined by the recurrence: F00 F11 FnFn-1Fn-2,n>2 Write a program to calculate the Fibon…

基于chatgpt动手实现一个ai_translator

动手实现一个ai翻译 前言 最近在极客时间学习《AI 大模型应用开发实战营》&#xff0c;自己一边跟着学一边开发了一个进阶版本的 OpenAI-Translator&#xff0c;在这里简单记录下开发过程和心得体会&#xff0c;供有兴趣的同学参考&#xff1b; ai翻译程序 版本迭代 在学习…

物联网设备的分类和功能阐述

物联网是将各种物理设备和传感器通过互联网进行连接和交互的网络&#xff0c;物联网的核心思想是让各种设备能够通过互联网实现智能化、自动化和远程控制。物联网设备是指连接到物联网中的各种设备&#xff0c;可以通过传感器、处理器、通信模块等技术实现与互联网的连接和数据…