安卓网络请求库Retrofit初探 | 青训营笔记
这是我参与「第四届青训营 」笔记创作活动的第3天
前言
不知道大家是否和我一样,我之前开发自己的小APP时其实很少去用网络库,平时就是okhttp或者说用原装做个工具类使用,但这样不免太麻烦了,今天这节课学到了一个新的请求库Retrofit。它的用法让我眼前一亮,我就觉得,诶这个很棒,特别是这种注释性开发,可以省去一些代码,而且用接口也会规范一些,很是喜欢。
那么对于初期使用,就要知道它的使用方式,为此我通过一个简单的爬虫APP,来记录这些请求的用法。
爬取对象
为了演示这个网络请求库简单的使用,我们爬取下B站的热词图鉴到APP。(仅仅做实践展示)
Retrofit
安装依赖
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
老师课上已经展示了这个,但是PPT课件又不能复制,找起来也比较麻烦,如果你刚好看见了,可以直接复制使用,这是目前文章发布时的最新版本,也是本次演示使用的。
接口实现
在请求之前,我们需要为请求创建一个接口类,在这里,我先创建一个名字为iBuzzwordInfoService的接口类,这里我首先展示一下自己的这个类。
在这个接口类里边我们需要去写一下我们的请求接口,把API的内容写在这里,这里是支持相对路径的,因此,你也注意到我没有去写域名,而是直接写了路径地址。
public interface IBuzzwordInfoService {
@GET("x/v2/dm/buzzword/list")
Call<ResponseBody> getHomeBuzzword(@Query("pn") int pn, @Query("ps") int ps, @Query("type_id") int typeId);
}
诶嘿,我们看看这个写法,是不是很棒,不知道大家是否喜欢,但是我是比较喜欢这种注解式写法的,可以省去一些代码,有点springboot的写法感觉了呢。
这样其实就简单的实现了一个GET请求接口的方法,留作备用,但在解释之前,我们先看看下面。
注解概述
我们首先注意到的就是@GET,这个东西就是注解,课堂上也讲了这个东西的原理,讲的是蛮不错的,不过这部分我吸收并不好,许多东西都是头一次听,没有太大概念。因此,这里就不过多阐述这个东西的底层了,
注解的话,按老师的说法
可以加在类、方法、参数、成员变量上,并且可在合适的时机读取注解的内容,进行处理
有三大情况下会处理这个注解,分别是:SOURSE,CLASS ,RUNTIME,对应着下面的情况。
-
注解只会保留在源文件中,编译时注解会被遗弃。
-
注解会保留到class文件中,当class文件中被加载时遗弃,这是默认的注解生命周期。
-
注解不仅被保留到class文件中,还会保留到虚拟机运行时一直存在。
那么我们我看看,刚刚的GET注解是在什么时候呢?按照之前课上讲的,我们看下这个@GET
这是一个注解类,毫不夸张的讲,对我来说,第一次见长这样的类,里边有个Retention,可以注意到是RUNTIME,那么就会按照第三种情况处理这个注解。
至于如何处理,现阶段知识有限,不能太快消化,就不扯了。
注解类型
我们刚刚见到了@GET("x/v2/dm/buzzword/list"),如此,这样我们可以去设置请求的路径,显然这是一个GET请求,但这显然不仅仅是全部,Retrofit支持的注解还有很多,相信如果你看了今天的课程就知道,当然如果没有看仅仅是在本文章了解到的,那么可以看看下图。
可以见到的,Retrofit支持着许多的注解,这对我们开发者而言是非常友好的,我可以仅仅使用它,就能办到目前使用到的基本请求。
动态路径
@GET("x/v2/dm/buzzword/list"),我们可以注意到这样的路径有时候不能满足我们的需求,因为它太固定了,为此课堂为我们展示了一种restful api的使用方式。
我们在路径里通过{key}来设置这个请求的参数标签,然后在方法中使用@Path(key)来注解一个变量,需要注意的是,他们的key名称得一样。
疑问:GET请求参数也能如此吗?
首先说结论,不能这样,我尝试把get参数也使用这种方式,但却收到了一个报错,提示我需要使用@Query(),换了之后果然没有报错。
请求演示
我们在前面暂时了如下图的一个接口类
我们注意到这个方法返回了一个Call,里边是ResponseBody,这个ResponseBody是retrofit封装的一个请求返回的信息,老师说我们也可以自定义这个实体类,当然这里是初次来使用,我们就按老师讲的用。
那么这里我们以这个GET请求作为演示,来看看retrofit的异步请求。
创建Retrofit实例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.bilibili.com/")
.build();
我们首先需要创建一个Retrofit实例,用来确定我们的请求域名。 这里我们需要注意到的是baseUrl可以设置请求域名,会搭配我们接口的路径组合起来。
创建接口实例并且获取Call
IBuzzwordInfoService iBuzzwordInfoService = retrofit.create(IBuzzwordInfoService.class);
Call<ResponseBody> call = iBuzzwordInfoService.getHomeBuzzword(1, 20, 4);
为了使用我们的接口类中定义的方法,这里我们首先要创建实例,并且获取call把我们的参数信息传进去。
异步请求获取数据
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call,Response<ResponseBody> response) {
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
}
});
这是最后一步棋子了,我们使用call.enqueue来发起请求,并且接收返回的信息,这里的两个方法分别对应着请求正常和失败的情况,我们可以在这里来操纵。
添加headers和获取headers
如果你的APP对请求需要有token了什么的在请求体里,或者爬虫什么的,需要设置headers,那么就需要了解到,我这里也统计出来了。
设置
方法一:在接口类的方法上面加这个,当有多个时使用{'',''}来添加更多。(静态)
@Headers("cookie:xxxxxx")
方法二:在注解里加入(动态)
@Header("Content-Range")
方法三:使用拦截器(这里就不阐述了)
获取
我们在返回里去调用它,就可以和获取到对应的
response.headers().get("content-type")
测试展示
我们使用response.body().string()获取到返回的内容,就可以把JSON转换成Java对象了,这样就可以使用了。
这里我更具前面几节课学的高级UI,实现了一个简单的不行的列表。
文末
感谢大家读到这里,这些就是我今天学到的内容了,如果大家发现有问题欢迎指出。