Android开发知识学习——从Retrofit原理来看HTTP

news2025/2/28 21:33:38

文章目录

  • Retrofit 使用方法简介
  • Retrofit 源码结构总结
  • 扔物线读源码的思路与方式

Retrofit 使用方法简介

  1. 导包
  implementation 'com.squareup.retrofit2:retrofit:最新版本'
  1. 创建一个 interface 作为 Web Service 的请求集合,在里面用注解
    (Annotation)写入需要配置的请求方法
    Java代码
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}

Kotlin代码

interface GitHubService {
    @GET("users/{user}/repos")
    fun listRepos(@Path("user") user: String?): Call<List<Repo>>
}
  1. 在正式代码里用 Retrofit 创建出 interface 的实例
    Java代码
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")v
.build();
GitHubService service =
retrofit.create(GitHubService.class);

Kotlin代码

//用Retrofit创建出interface的实例
        val retrofit: Retrofit = Retrofit.Builder()
            .baseUrl("https://api.github.com/")
            .build()
        val service:GitHubService = retrofit.create(GitHubService::class.java)
  1. 调用创建出的 Service 实例的对应方法,创建出相应的可以用来发起网络请求的
    Call 对象
    Java代码
Call<List<Repo>> repos = service.listRepos("octocat");

Kotlin代码

//创建出service实例的对应方法,创建出对应的可以用来发送网络请求的call对象
        val repos :Call<List<Repo>> = service.listRepos("octocat")
  1. 使用 Call.execute() 或者 Call.enqueue() 来发起请求
    Java代码
repos.enqueue(callback);

Kotlin代码

//使用 Call.execute() 或者 Call.enqueue() 来发起请求
repos.enqueue(callback);
repos.enqueue(object : Callback<List<Repo>?>  {
            override fun onResponse(call: Call<List<Repo>?>, response: Response<List<Repo>?>) {
                TODO("Not yet implemented")
            }

            override fun onFailure(call: Call<List<Repo>?>, t: Throwable) {
            }
        })

在这里插入图片描述
在这里插入图片描述

Retrofit 源码结构总结

通过 Retrofit.create(Class) 方法创建出 Service interface 的实例,从
而使得 Service 中配置的方法变得可用,这是 Retrofit 代码结构的核心;
Retrofit.create() 方法内部,使用的是
Proxy.newProxyInstance() 方法来创建 Service 实例。这个方法会为参
数中的多个 interface (具体到 Retrofit 来说,是固定传入一个 interface)创建
一个对象,这个对象实现了所有 interface 的每个方法,并且每个方法的实现都
是雷同的:调用对象实例内部的一个 InvocationHandler 成员变量的
invoke() 方法,并把自己的方法信息传递进去。这样就在实质上实现了代理
逻辑:interface 中的方法全部由一个另外设定的 InvocationHandler 对象
来进行代理操作。并且,这些方法的具体实现是在运行时生成 interface 实例时
才确定的,而不是在编译时(虽然在编译时就已经可以通过代码逻辑推断出
来)。这就是网上所说的「动态代理机制」的具体含义。
因此, invoke() 方法中的逻辑,就是 Retrofit 创建 Service 实例的关键。这
个方法内有三行关键代码,共同组成了具体逻辑:

  1. ServiceMethod 的创建:
loadServiceMethod(method)

这行代码负责读取 interface 中原方法的信息(包括返回值类型、方法注解、参
数类型、参数注解),并将这些信息做初步分析。实际返回的是一个
CallAdapted 。

  1. OkHttpCall 的创建:
new OkHttpCall<>(requestFactory, args, callFactory,
responseConverter)

OkHttpCall 是 retrofit2.Call 的子类。这行代码负责将
ServiceMethod 解读到的信息(主要是一个 RequestFactory 、一个
OkHttpClient 和一个 ResponseConverter )封装进 OkHttpCall ;
而这个对象可以在需要的时候(例如它的 enqueue() 方法被调用的时候),
利用 RequestFactory 和 OkHttpClient 来创建一个 okhttp3.Call
对象,并调用这个 okhttp3.Call 对象来进行网络请求的发起,然后利用
ResponseConverter 对结果进行预处理之后,交回给 Retrofit 的
Callback 。
3. adapt() 方法:

callAdapter.adapt(call);

这个方法会使用一个 CallAdapter 对象来把 OkHttpCall 对象进行转换,生成一个新的对象。默认情况下,返回的是一个 ExecutorCallbackCall ,它的作用是把操作切回主线程后再交给 Callback 。
另外,如果有自定义的 CallAdapter,这里也可以生成别的类型的对象,例如RxJava 的 Observable ,来让 Retrofit 可以和 RxJava 结合使用。

  • 更细的代码逻辑(例如 ServiceMethod 如何做方法解析、CallAdapter 如何做adapt,就不在讲义里再总结一遍了,可以看课上的分析)

扔物线读源码的思路与方式

  • 寻找切入点,而不是逐行通读

    • 理想情况下,逐行通读可以最高效率读通一个项目的代码,因为每行代码都只需要读一遍;但实时情况下,逐行通读会导致脑中积累太多没有成体系的代码,导致你读个几十几百行就读不下去了,因此一点也不实用。而从切入点开始读,可以在最快时间内把看到的代码体系化,形成一个「完整的小世界」;在把「小世界」看明白之后,再去一步步扩大和深入,就能够逐渐掌握更多的细节。
    • 寻找切入点的方式:离你最近的位置就是切入点,通常是业务代码中的最后一行。
    • 以 Retrofit 为例,最后的 Call.enqueue() 会被我作为切入点;在尝试从 Call.enqueue() 切入失败后,逐步回退到 Retrofit.create()方法,找到项目结构的核心,然后开始继续发散和深入。
  • 在阅读过程中,始终保有把看过的代码逻辑完整化的意识

    • 代码阅读过程中,不懂的代码会越来越多,脑子就会越来越乱。如果不断尝试把看到的代码结合起来组合成完整逻辑,就能让头脑始终保持清晰,而不是深入到某个细节好久之后忽然一抬头:「我为什么点进这个方法来着?」可以试着在读源码的时候,经常把多行或多段代码在脑子里(或者笔记里)
      组合成一整块,从而让代码结构更清晰,让阅读过程不断增加进度感,也减小继续阅读的难度。
    • 以 Retrofit 为例,当读懂 Proxy.newProxyInstance() 方法实际上是创建了一个代理对象的时候,可以停下来做一个总结:「这是 Retrofit 的大框架」,在脑子里或者笔记上都可以。总结消化过后,再继续阅读。
  • 尽量让每一刻都有一个确定的目标

    • 读代码经常会出现「横向逻辑还没看清晰,纵向深度也没挖透」的情况。那么到底是要横向扩展阅读结构,还是纵向挖深度,最好是在每次遇到这种分岔路口的时候就先做好决定。不能在每个分岔路口都想也不想地看到不懂的就追下去,容易迷路。
    • 在遇到「横向也广,纵向也深」的时候,根据情况选择其中一个就好,并没有必然哪种选择更优的铁律。而如果遇到越钻越头大的情况,可以退回之前的某一步,换条路继续走。换路的时候记得做好标记:「我在哪里探路失败了」。

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

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

相关文章

Unity Shader Graph HDRP Reflections Cubemap

主贴图 与 反射 过渡 可调节 因为shader graph 版本原因&#xff0c;略微跟教程不太一样 教程链接&#xff1a; https://www.youtube.com/watch?v943P0dGR4rQ

uniapp leven系列原生插件(1)

目录 1.乐橙摄像机播放插件(云台对讲版) 插件介绍 插件地址 预览图片 ​编辑 2.乐橙摄像机播放插件(子账号云台对讲版) 插件介绍 插件地址 预览图片 ​编辑 3.无预览静默拍照 插件介绍 插件地址 预览图片 4.视频图片选择安卓原生插件 插件介绍 插件地址 预览图…

抖音双11好物节抢跑,这5家品牌联动巨量引擎解锁新增量

截止10月23日&#xff0c;抖音商城整体GMV对比去年同期提升200%。HBN、蓝月亮、万益蓝WONDERLAB、海尔、海澜之家等商家在抖音双11好物节&#xff0c;通过巨量引擎实现提前拓量&#xff0c;效果出众。 其中&#xff0c;HBN在抖音双11好物节抢跑期&#xff0c;通过TopLive直播加…

打造教育新高地 | 拓世法宝AI智能直播一体机,教育界的不二之选

教育是社会进步和个人成长的基石&#xff0c;它不仅是知识传授的载体&#xff0c;更是塑造未来社会精英的摇篮。近年来&#xff0c;数字化、智能化以及个性化教育模式成为当下教育改革的关键词&#xff0c;它不断引领着人类文明的发展&#xff0c;开启着每个人成长的无限可能。…

VS2017制作安装包如何将整个文件夹添加进依赖项中

找到安装项目右键view-文件系统 找到Application Folder 右键Add-Folder 如Python38 选中创建的 Python38 在右侧的空白处粘贴要复制的文件即可。文件多&#xff0c;等待时间较长

铜排载流量表新垂直拼接表-分享一张铜排的载流量表可以方便查看铜排重量计算

可以方便的铜排重量的铜排载流量表来了&#xff0c;方便查询和选择&#xff0c;希望能够帮到你&#xff1a; 下载&#xff1a;https://download.csdn.net/download/weixin_43097956/88490649

正点原子嵌入式linux驱动开发——Linux USB驱动

USB是很常用的接口&#xff0c;目前大多数的设备都是USB接口的&#xff0c;比如鼠标、键盘、USB摄像 头等&#xff0c;在实际开发中也常常遇到USB接口的设备&#xff0c;本章就来学习一下如何使能Linux内核自带的USB驱动。这里不会具体学习USB的驱动开发。 USB接口简介 什么是…

CSS内容过多保留固定字数并显示省略号

一、业务场景&#xff1a; 详情内容过多时&#xff0c;会使布局错乱&#xff0c;需要保留固定的字数&#xff0c;鼠标划上显示出全部内容 三、具体实现步骤&#xff1a; <a-tooltip><template slot"title">{{lastChe}}</template><span class…

详解Java经典数据结构——HashMap

Java 的 HashMap 是一个常用的基于哈希表的数据结构&#xff0c;它实现了 Map 接口&#xff0c;可以存储键值对。下面我们进行详细介绍&#xff1a; 基本结构&#xff1a;HashMap 底层是基于哈希表来实现的&#xff0c;每次插入一个键值对时&#xff0c;会先对该键进行 Hash 运…

微信小程序导入js使用时候报错

我是引入weapp库时候&#xff0c;导入js会报错。 需要在小程序开发工具里面配置 就可以了。

视频剪辑小技巧:批量调整视频色调,让你的视频更出色

在视频剪辑过程中&#xff0c;批量调整视频色调是一项非常重要的技巧。通过调整视频色调&#xff0c;你可以让视频更加生动、富有表现力&#xff0c;并创造出独特的视觉效果。本文将介绍云炫AI智剪的批量调整视频色调小技巧&#xff0c;帮助你提升视频品质。以下是具体的操作步…

在 Typescript 项目中使用 cdn 加载的js插件没有类型声明

先上一段同事写得代码, 此处动态的插入了 MathJax 这个 js 插件, 我不知道为什么如此编写, //ts-ignore 此处不知道为什么如此调用, 只能使用 ts-ignore 忽略dynamicLoadingJs("//xxx.com/latex/MathJax.js?configTeX-AMS_HTML", () > {MathJax.Hub.Config({exte…

2023-11-01 LeetCode每日一题(参加会议的最多员工数)

2023-11-01每日一题 一、题目编号 2127. 参加会议的最多员工数二、题目链接 点击跳转到题目位置 三、题目描述 一个公司准备组织一场会议&#xff0c;邀请名单上有 n 位员工。公司准备了一张 圆形 的桌子&#xff0c;可以坐下 任意数目 的员工。 员工编号为 0 到 n - 1 。…

高浓度工业废水处理设备有哪些

高浓度工业废水处理设备主要有以下几种&#xff1a; 水解酸化池&#xff1a;将有机废水通过水解、酸化作用&#xff0c;使其成为更易于生化降解的有机物。厌氧池&#xff1a;通过厌氧反应降解有机废水&#xff0c;产生沼气等可再利用资源。好氧池&#xff1a;将经过水解酸化或…

TikTok趋势分析:社交媒体的下一个风向标

社交媒体一直是信息传播和娱乐的前沿阵地&#xff0c;而TikTok&#xff08;抖音&#xff09;已然成为这一领域的新宠。其独特的短视频内容和强大的算法推荐系统吸引了数十亿用户&#xff0c;不仅改变了用户的娱乐习惯&#xff0c;还重新定义了社交媒体的面貌。本文将深入探讨Ti…

如何实现精确IP地址定位:技术和隐私的平衡

精确的IP地址定位可以为各种应用提供重要的信息&#xff0c;从网络安全到市场分析。然而&#xff0c;这一过程涉及到技术、法律和伦理等多方面的问题。本文将探讨如何实现精确IP地址定位&#xff0c;并同时平衡技术与隐私之间的挑战。 IP地址定位的背景 1. IP地址的基本概念 …

JAVA 实现PDF转图片(pdfbox版)

依赖&#xff1a; pdf存放路径 正文开始&#xff1a; pdf转换多张图片、长图 Test void pdf2Image() {String dstImgFolder "";String PdfFilePath "";String relativelyPathSystem.getProperty("user.dir");PdfFilePath relativelyPath &qu…

使用vue3+vite+elctron构建小项目介绍Electron进程间通信

进程间通信 (IPC) 是在 Electron 中构建功能丰富的桌面应用程序的关键部分之一。 由于主进程和渲染器进程在 Electron 的进程模型具有不同的职责&#xff0c;因此 IPC 是执行许多常见任务的唯一方法&#xff0c;例如从 UI 调用原生 API 或从原生菜单触发 Web 内容的更改。 在 …

【嵌入式开发学习02】esp32cam烧录human_face_detect实现人脸识别

Ubuntu20.04系统为esp32cam烧录human_face_detect 1. 下载esp-dl2. 安装esp-idf3. 烧录human_face_detect 如果使用ubuntu 16.04在后续的步骤中会报错如下&#xff0c;因为ubuntu 16.04不支持glibc2.23以上的版本&#xff08;可使用strings /lib/x86_64-linux-gnu/libc.so.6 | …

抖音直播招聘报白与求职者互动的招聘方式企业或者人力资源公司

人力资源行业抖音招聘报白开始了&#xff0c;但是目前的市面的价格不一&#xff0c;很多人力资源公司最近想做抖音的直播报白&#xff0c;做直播待岗&#xff0c;因为最近刚好是招聘高峰期啊&#xff0c;企业需求大&#xff0c;赶上这一波&#xff0c;但是对目前市面上做抖音报…