好用的网络请求库Retrofit2(入门及讲解)

2023-11-18

前言

首先,先给出官网:

GitHub-Retrofit
官网-Retrofit

其次,要吐槽一下官网首页给出的例子。如果你照着例子改,会发现根本没法运行,不是少包就是少关键语句。

相关内容可以参看我的另一篇文章:Retrofit(2.0)入门小错误 – Could not locate ResponseBody xxx Tried: * retrofit.BuiltInConverters

小栗子(example)

无论如何咱们还是先跑起来一个小栗子吧。

首先,在gralde文件中引入后续要用到的库。


compile 'com.squareup.retrofit:retrofit:2.0.0-beta2'
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'
compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta2'

compile 'com.squareup.okhttp:okhttp:2.4.0'

compile 'io.reactivex:rxjava:1.0.14'
compile 'io.reactivex:rxandroid:1.0.1'

接下来跟着我一步两步往下走。

创建服务类和Bean

 public static class Contributor {
   public final String login;
    public final int contributions;
    public Contributor(String login, int contributions) {
        this.login = login;
        this.contributions = contributions;
    }
    @Override
    public String toString() {
        return "Contributor{" +
                "login='" + login + '\'' +
                ", contributions=" + contributions +
                '}';
    }
}
public interface GitHub {
    @GET("/repos/{owner}/{repo}/contributors")
    Call<List<Contributor>> contributors(
            @Path("owner") String owner,
            @Path("repo") String repo);
}

接下来创建Retrofit2的实例,并设置BaseUrl和Gson转换。

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.github.com")
        .addConverterFactory(GsonConverterFactory.create())
        .client(new OkHttpClient())
        .build();

创建请求服务,并为网络请求方法设置参数

GitHub gitHubService = retrofit.create(GitHub.class);
Call<List<Contributor>> call = gitHubService.contributors("square", "retrofit");

最后,请求网络,并获取响应

try{
    Response<List<Contributor>> response = call.execute(); // 同步
    Log.d(TAG, "response:" + response.body().toString());
} catch (IOException e) {
    e.printStackTrace();
}

Call是Retrofit中重要的一个概念,代表被封装成单个请求/响应的交互行为

通过调用Retrofit2的execute(同步)或者enqueue(异步)方法,发送请求到网络服务器,并返回一个响应(Response)。

  1. 独立的请求和响应模块
  2. 从响应处理分离出请求创建
  3. 每个实例只能使用一次。
  4. Call可以被克隆。
  5. 支持同步和异步方法。
  6. 能够被取消。

由于call只能被执行一次,所以按照上面的顺序执行会得到如下错误。

java.lang.IllegalStateException: Already executed

我们可以通过clone,来克隆一份call,从新调用。

// clone
Call<List<Contributor>> call1 = call.clone();
// 5. 请求网络,异步
call1.enqueue(new Callback<List<Contributor>>() {
    @Override
    public void onResponse(Response<List<Contributor>> response, Retrofit retrofit) {
        Log.d(TAG, "response:" + response.body().toString());
    }

    @Override
    public void onFailure(Throwable t) {

    }
});

参数相关

网络访问肯定要涉及到参数请求,Retrofit为我们提供了各式各样的组合方法。下面以标题+小例子的方式给出讲解。

固定查询参数
// 服务
interface SomeService {
 @GET("/some/endpoint?fixed=query")
 Call<SomeResponse> someEndpoint();
}

// 方法调用
someService.someEndpoint();

// 请求头
// GET /some/endpoint?fixed=query HTTP/1.1
动态参数
// 服务
interface SomeService {
 @GET("/some/endpoint")
 Call<SomeResponse> someEndpoint(
 @Query("dynamic") String dynamic);
}

// 方法调用
someService.someEndpoint("query");

// 请求头
// GET /some/endpoint?dynamic=query HTTP/1.1

动态参数(Map)

// 服务
interface SomeService {
 @GET("/some/endpoint")
 Call<SomeResponse> someEndpoint(
 @QueryMap Map<String, String> dynamic);
}

// 方法调用
someService.someEndpoint(
 Collections.singletonMap("dynamic", "query"));
// 请求头
// GET /some/endpoint?dynamic=query HTTP/1.1
省略动态参数
interface SomeService {
 @GET("/some/endpoint")
 Call<SomeResponse> someEndpoint(
 @Query("dynamic") String dynamic);
}

// 方法调用
someService.someEndpoint(null);

// 请求头
// GET /some/endpoint HTTP/1.1
固定+动态参数
interface SomeService {
 @GET("/some/endpoint?fixed=query")
 Call<SomeResponse> someEndpoint(
 @Query("dynamic") String dynamic);
}

// 方法调用
someService.someEndpoint("query");

// 请求头
// GET /some/endpoint?fixed=query&dynamic=query HTTP/1.1
路径替换
interface SomeService {
 @GET("/some/endpoint/{thing}")
 Call<SomeResponse> someEndpoint(
 @Path("thing") String thing);
}

someService.someEndpoint("bar");

// GET /some/endpoint/bar HTTP/1.1
固定头
interface SomeService {
 @GET("/some/endpoint")
 @Headers("Accept-Encoding: application/json")
 Call<SomeResponse> someEndpoint();
}

someService.someEndpoint();

// GET /some/endpoint HTTP/1.1
// Accept-Encoding: application/json
动态头
interface SomeService {
 @GET("/some/endpoint")
 Call<SomeResponse> someEndpoint(
 @Header("Location") String location);
}

someService.someEndpoint("Droidcon NYC 2015");

// GET /some/endpoint HTTP/1.1
// Location: Droidcon NYC 2015
固定+动态头
interface SomeService {
 @GET("/some/endpoint")
 @Headers("Accept-Encoding: application/json")
 Call<SomeResponse> someEndpoint(
 @Header("Location") String location);
}

someService.someEndpoint("Droidcon NYC 2015");

// GET /some/endpoint HTTP/1.1
// Accept-Encoding: application/json
// Location: Droidcon NYC 2015
Post请求,无Body
interface SomeService {
 @POST("/some/endpoint")
 Call<SomeResponse> someEndpoint();
}

someService.someEndpoint();

// POST /some/endpoint?fixed=query HTTP/1.1
// Content-Length: 0
Post请求有Body
interface SomeService {
 @POST("/some/endpoint")
 Call<SomeResponse> someEndpoint(
 @Body SomeRequest body);
}

someService.someEndpoint();

// POST /some/endpoint HTTP/1.1
// Content-Length: 3
// Content-Type: greeting
//
// Hi!
表单编码字段
interface SomeService {
 @FormUrlEncoded
 @POST("/some/endpoint")
 Call<SomeResponse> someEndpoint(
 @Field("name1") String name1,
 @Field("name2") String name2);
}

someService.someEndpoint("value1", "value2");

// POST /some/endpoint HTTP/1.1
// Content-Length: 25
// Content-Type: application/x-www-form-urlencoded
//
// name1=value1&name2=value2
表单编码字段(Map)
interface SomeService {
 @FormUrlEncoded
 @POST("/some/endpoint")
 Call<SomeResponse> someEndpoint(
 @FieldMap Map<String, String> names);
}

someService.someEndpoint(
 // ImmutableMap是OKHttp中的工具类
 ImmutableMap.of("name1", "value1", "name2", "value2"));

// POST /some/endpoint HTTP/1.1
// Content-Length: 25
// Content-Type: application/x-www-form-urlencoded
//
// name1=value1&name2=value2

动态Url(Dynamic URL parameter)

interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 Call<List<Contributor>> repoContributors(
 @Path("owner") String owner,
 @Path("repo") String repo);

 @GET
 Call<List<Contributor>> repoContributorsPaginate(
 @Url String url);
}

// 调用
Call<List<Contributor>> call = gitHubService.repoContributors("square", "retrofit");
Response<List<Contributor>> response = call.execute();
// 响应结果
// HTTP/1.1 200 OK
// Link: <https://api.github.com/repositories/892275/contributors?
page=2>; rel="next", <https://api.github.com/repositories/892275/
contributors?page=3>; rel="last"

// 获取到头中的数据
String links = response.headers().get("Link");
String nextLink = nextFromGitHubLinks(links);
// https://api.github.com/repositories/892275/contributors?page=2

可插拔的执行机制(Multiple, pluggable execution mechanisms)

interface GitHubService {
 @GET("/repos/{owner}/{repo}/contributors")
 // Call 代表的是CallBack回调机制
 Call<List<Contributor>> repoContributors(
 @Path("owner") String owner,
 @Path("repo") String repo);

 @GET("/repos/{owner}/{repo}/contributors")
 // Observable 代表的是RxJava的执行
 Observable<List<Contributor>> repoContributors2(
 @Path("owner") String owner,
 @Path("repo") String repo);

 @GET("/repos/{owner}/{repo}/contributors")
 Future<List<Contributor>> repoContributors3(
 @Path("owner") String owner,
 @Path("repo") String repo);
}

注意,要在构建Retrofit时指定适配器模式为RxJavaCallAdapterFactory

Retrofit retrofit = new Retrofit.Builder()
    .addConverterFactory(GsonConverterFactory.create())
    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
    .baseUrl("http://www.duitang.com")
    .build();

否则,会报出如下错误:

Caused by: java.lang.IllegalArgumentException: Could not locate call adapter for rx.Observable<com.bzh.sampleretrofit.ClubBean>. Tried:
* retrofit.ExecutorCallAdapterFactory

Retrofit执行模式

最后

授人以鱼不如授人以渔 这是出自官方开发人员的讲解的网站(自备梯子)

Retrofit作为一个上层框架,自然有很多底层lib库支持,okiookhttp都包含其中。

这是一些关于OK库的讲解

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

好用的网络请求库Retrofit2(入门及讲解) 的相关文章

  • 使用DBFlow,如何加密已经存在的数据库?

    我正在使用 DBFlow 来处理项目中的数据库 并且我想对现有数据库进行加密 我知道我可能必须删除现有的未加密数据库并创建另一个加密数据库 我也知道我可以将 SQLCipher 与 DBFlow 一起使用 如上所述文档 https gith
  • Android EditText 和 addTextChangedListener

    我目前正在将数据库管理器移植到 Android 由于性能原因 我喜欢 仅更新已修改的属性 我尝试使用 addTextChangedListener 执行此操作 以便将修改后的条目添加到列表中 但我的程序从未输入其任何方法 EditText
  • 我无法再在后台应用程序中接收任何 FCM 消息

    当应用程序处于后台时 我无法再在应用程序中接收任何数据消息 请注意 直到最近它在我的应用程序中都运行良好 也许在我的开发环境最近更新后它停止工作了 我不能说 所以我尝试用快速入门 android 项目 https github com fi
  • 无法在 Android Studio 中导出签名的 APK

    当我使用keytool list keystore path to keyfile jks并提供我的密码 我可以看到那里的条目 但是当我在尝试使用相同的密码生成签名的 APK 时使用相同的密码时 我收到错误 无法加载密钥库 密钥库被篡改 或
  • 嵌套 XML 布局文件

    android 有没有办法从另一个布局文件引用 xml 布局文件 为了更好地解释 我有一个名为layout1 xml 和layout2 xml 的布局文件 我可以从layout1 xml引用layout2 xml吗 用这个
  • 当我单击“完成”键时,Android OnEditorActionListener() actionId 给出 0

    我创建了一个键盘 当用户输入数字时 它会输入特定的 EditText 但是当用户单击Done关键 它没有去setOnEditorActionListener但它关闭了键盘 这是我的代码 final EditText txtQty new E
  • relativelayout导致动画不起作用?

    我有一个活动 其布局仅包含一个 VideoView 这是 XML
  • 如何使用 Google 的 GithubBrowserSample 方法在片段之间共享视图模型?

    我对 Android 架构组件的使用非常陌生 因此我决定使用 GithubBrowserSample 来构建我的应用程序来实现我的许多用例 但我有一个问题 我不知道使用这种方法在片段之间共享视图模型的正确方法是什么 我想共享视图模型 因为我
  • Android L,使用 joda.time 库的异常

    该应用程序适用于所有设备 包括 nexus 5 和 nexus 7 在 Android L 预览版上运行相同的应用程序时 应用程序崩溃了 我一直在调试 并且调用 DateTime 构造函数发现了异常 public static String
  • 我在 android studio 中使用 kotlin 时出现错误

    为什么会出现这个错误 09 12 16 36 31 502 1886 1886 com getloction nourmedhat smartgate getlocation E AndroidRuntime 致命异常 main 进程 co
  • 如何将 JSON 数据从 Android 发送到 php url?

    我想将登录信息从我的应用程序发送到 php url 因为这我的应用程序将崩溃 任何人都可以帮助我解决这个问题 这是我的服务器登录方法 我想将数据发送到此登录方法 Method public method login Parameters 3
  • 文本视图不显示全文

    我正在使用 TableLayout 和 TableRow 创建一个简单的布局 其中包含两个 TextView 这是代码的一部分
  • 使 Recyclerview 固定高度并可滚动

    已解决以下检查答案 所以我试图为我的 Android 应用程序创建评论功能 我想在 recyclerview 中显示评论 然后在 recyclerview 下方有一个按钮和文本视图来添加评论 我想让 recyclerview 具有一定的高度
  • 通过 Gradle 和 Android Studio 构建和运行应用程序比通过 Eclipse 慢

    我有一个多项目 10 个模块 每次构建大约需要 20 30 秒 当我在 Android Studio 中按 运行 时 每次都必须等待才能重建应用程序 这非常慢 是否可以在 Android Studio 中自动化构建过程 或者您对如何加快此过
  • Android ScrollView,检查当前是否滚动

    有没有办法检查标准 ScrollView 当前是否正在滚动 方向是向上还是向下并不重要 我只需要检查它当前是否正在滚动 ScrollView当前形式不提供用于检测滚动事件的回调 有两种解决方法可用 1 Use a ListView并实施On
  • TabLayout 的不同 tabMode

    我正在使用 ViewPager 和 TabLayout 如果选项卡可以放置在显示 tabMode 上 则它们必须是 app tabMode fixed else app tabMode scrollable 我怎样才能做到这一点 我不明白你
  • Android 从通知刷新 Activity

    我有一个程序 我在其中调用通知 如果您将其下拉 该通知将启动一个新活动 mNotificationManager NotificationManager getSystemService ns int icon R drawable sta
  • 动态更改按钮上的图像视图

    在我的应用程序中 我有按钮和ImageView 当我按下按钮时我想改变ImageView 我的可绘制文件夹中有 5 张图像 按下按钮时 ImageView 根据按钮单击一张一张地更改图像 我想要它的解决方案 感谢任何可以提供帮助的人 维护一
  • 在数组列表中过滤 Filterable 不取消之前的过滤

    我看过过滤器方法文档 其中显示调用过滤器会取消所有先前未执行的过滤请求 并发布一个稍后将执行的新过滤请求 但我收到的实际回调有些不同 在我的实现中 它不会取消先前的过滤器请求并调用publishResults 最近一次搜索条件后的上一次搜索
  • 如何用LoaderManager自动重新查询

    我有一个应用程序显示来自 SQLite DB 的数据 并且数据不断变化 所以显然 我认为我应该使用 LoaderManager 来显示数据 我读过一些关于将 LoaderManager 与 SQLite 结合使用的内容 然后看到了亚历克斯

随机推荐

  • 基于STC8G1K08A的可调节占空比和频率的PWM应用案例

    基于STC8G的可调节占空比和频率的PWM应用案例 CSDN的小白分享 前言 一 STC8G系列的介绍 二 使用记录 1 建立工程 2 打开工程所需的芯片功能 及本人的函数 总结 CSDN的小白分享 前言 学习单片机以来 都是写了就算的态度
  • 如何在Rich Edit Control中管理超链接

    如何在Rich Edit Control中管理超链接 一 在Rich Edit Control 中显示超链接 在Rich Edit Control 中显示超链接的格式 也就是给选择的文本添加CFE LINK属性 可以通过以下两种方法实现 1
  • 详解MNIST数据集下载、解析及显示的Python实现

    Content MNIST数据集基本介绍 下载MNIST数据集到本地 解析MNIST数据集 显示MNIST数据集中训练集的前9张图片和标签 随着图像处理 计算机视觉 机器学习 甚至深度学习的蓬勃发展 一个良好的数据集作为学习和测试相关算法非
  • python编程基础-task4-FOR、IF以及while

    一 IF语句 avg 90 math 95 Chinese 85 if math lt Chinese print 语文更好 if math gt Chinese print 数学更好 Chinese 5 if avg Chinese pr
  • 实战:实现缓存和数据库一致性方案

    原创 微信公众号 阿Q说代码 欢迎分享 转载请保留出处 哈喽大家好 我是阿Q 最近不是正好在研究 canal 嘛 刚巧前两天看了一篇关于解决缓存与数据库一致性问题的文章 里边提到了一种解决方案是结合 canal 来操作的 所以阿Q就想趁热打
  • 中达优控触摸屏编程视频教程_触摸屏组态编程软件

    YKBuilder是一个中达优控触摸屏编程软件 触摸屏组态编程软件在电脑的开始菜单 打开运行对话框 输入 dcslic gt 确定启动 Licenses 管理工具 触摸屏组态编程软件 YKBuilder是中达优控YKHMI系列人机界面的集成
  • curl在windows的安装和使用

    经常看到别人在用curl命令可以请求各种网络请求在命令行里 看起来挺炫酷的 curl作为一个请求web服务器的命令行工具 玩得好甚至可以代替postman 这里我就是讲一下关于如何安装curl在windows上 毕竟很多时候用的电脑都是公司
  • LDAP未授权漏洞验证

    因为工作需要 这里验证了下LDAP未授权 以下是收集到的资料 最后是具体使用 更新 2 连接ad域有两个地址 ldap http XXXXX com 389 和 ldap http XXXXX com 636 SSL 3 端口389用于一般
  • 根据接口数据返回的不同字段显示不同背景颜色

    结构 div span item hldj substr 0 2 span substr 0 2 要抽取的子串的起始下标 从0开始截取2位 如南一公园只会显示南一 div 交互 methods toHldj item if item hld
  • 制作镜像并上传到阿里云

    run一个ubuntu容器 然后自动进入容器 ucsmy QKTEST21191 docker run it name node daocloud io ubuntu root 3ac09729dadb 安装geth sudo apt ge
  • 使用Bootstrap样式的死的简单Vue分页组件

    网页 vue pages A Dead Simple Vue Pagination Component Using Bootstrap Style 使用Bootstrap样式的死的简单Vue分页组件 support vue 2 0 支持vu
  • Unity的C#编程教程_52_类 Class 详解及应用练习(一)

    文章目录 C Classes for Behaviours Custom Classes 1 Custom Classes 2 Serialized Custom Class RPG Item Database Example 3 When
  • C++的tuple

    一 介绍 tuple是一个固定大小的不同类型值的集合 是泛化的std pair 我们也可以把它当做一个通用的结构体来用 不需要创建结构体又获取结构体的特征 在某些情况下可以取代结构体使程序更简洁 直观 std tuple理论上可以有无数个任
  • react项目配置@指向src文件夹

    react项目配置 指向src文件夹 react项目没有和vue一样有 指向src文件夹 需要手动配置 配置了之后 就代表 src 目录 就不用自己 暴露项目配置项 任选一种 npm方式 npm run eject cnpm方式 cnpm
  • C++获取电脑主板唯一标识

    获取电脑的唯一标识有很多好处 比如注册 授权等 而且电脑中有很多是唯一标识的硬件 比如网卡 CPU 硬盘 主板等 但是如果电脑中有两个网卡的话 就不知道使用哪个网卡作为唯一的了 可以通过获取主板的ID 作为唯一的标识 通常情况下 可以通过命
  • 无限法则服务器错误登录期间发生错误,无限法则错误126的解决方案分享 Error126错误提示...

    无限法则错误126的解决方案分享 Error126错误提示 许多玩家在玩游戏时遇到了Error126的情况 那么出现这个问题该怎么解决呢 无限法则Error126报错解决方法希望对大家有所帮助 问题描述 出现Error 126错误提示 12
  • win10 win11 远程连接 凭据不工作 无法建立连接

    Windows 远程连接 远程连接个人或者学校电脑 Windows系统 时经常遇到无法连接的情况 本文结合两种情况给出相应解决方法 No 1 问题描述 无法建立连接 未知连接错误 解决方法 查看目标ipv4地址是否正确 在windows W
  • 【JavaWeb学习】CSS(文本和图片)

    字体 color 前景色 用来设置字体的颜色 font size 字体大小 font family 字体族 指定字体的类别 浏览器自动使用该类别下的字体 可以同时指定多个字体 多个字体间用逗号隔开 前一个无法使用就用后一个 字体能否使用由用
  • (邱维声)高等代数课程笔记:极大线性无关组,向量组的秩

    极大线性无关组 向量组的秩 quad 一般地 设 V V V 是数域 K K K 上的一个线性空间
  • 好用的网络请求库Retrofit2(入门及讲解)

    前言 首先 先给出官网 GitHub Retrofit 官网 Retrofit 其次 要吐槽一下官网首页给出的例子 如果你照着例子改 会发现根本没法运行 不是少包就是少关键语句 相关内容可以参看我的另一篇文章 Retrofit 2 0 入门