Retrofit
是Square
公司开发的一款针对Android
和java
的网络请求框架,遵循Restful
设计风格,底层基于OkHttp
。
Retrofit具有以下主要功能:
Gson
、json
、XML
等等)Rxjava
的支持高度解耦,使用方便相比去其他网络请求框架,其具有性能特别棒、使用特别方便的特性,所以在任何网络请求场景下,我们都应该有限考虑Retrofit
,本文就Retrofit
的入门使用和简单特性做简单介绍,抛砖引玉,希望大家可以爱上Retrofit
。
我们首先通过一个简单的案例带大家走一遍使用Retrofit的完整流程,然后再深入介绍Retrofit的一些特性。
我们要做的就是在Android中使用Retrofit发起网络请求,将下图(图片地址:http://picture-pool.oss-cn-beijing.aliyuncs.com/2019-06-29-121904.png
)下载并展示出来,下面我来一步一步介绍如何去做。
在Gradle
文件中添加如下依赖:
implementation 'com.squareup.retrofit2:retrofit:2.6.0'
在Android
的manifest
配置文件中声明网络请求权限:
Retrofit
将 Http
请求抽象成 Java
接口,采用注解来描述配置网络请求参数,何为配置网络请求参数?说白了就是设置网络请求的地址是什么、使用什么请求方法、传递的参数是什么、返回值类型是什么等等一系列配置信息,通过接口描述清楚这些具体的网络配置信息,Retrofit
才能根据你的配置发起最终的网络请求。所以我们首先应该声明一个用于配置网络请求的Java
接口:
/**
* @author dmrfcoder
* @date 2019-06-29
*/
public interface GetRequestInterface {
/**
*
*
* 通过get()方法获取图片的请求接口
* GET注解中的参数值"2019-06-29-121904.png"和Retrofit的base url拼接在一起就是本次请求的最终地址
*
* @return
*
*/
@GET("2019-06-29-121904.png")
Call<ResponseBody> getPictureCall();
}
这里直接给出代码,重点都在注释中:
public void retrofitGet() {
/*
创建Retrofit对象,这里设置了baseUrl,注意我们在声明网络配置接口GetRequestInterface的时候在GET注解中也声明了一个Url,
我们将会这里的baseUrl和GET注解中设置的Url拼接之后就可以形成最终网络请求实际访问的url
*/
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://picture-pool.oss-cn-beijing.aliyuncs.com/").build();
//创建网络请求配置的接口实例
GetRequestInterface getRequestInterface = retrofit.create(GetRequestInterface.class);
//调用我们声明的getPictureCall()方法创建Call对象
Call<ResponseBody> requestBodyCall = getRequestInterface.getPictureCall();
//使用requestBodyCall发起异步网络请求
requestBodyCall.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
//将网络请求返回的数据解析为图片并展示到界面
ResponseBody body = response.body();
InputStream inputStream = body.byteStream();
Drawable drawable = Drawable.createFromStream(inputStream, "pic.png");
imageView.setBackground(drawable);
Log.e(TAG, "网络请求成功");
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.e(TAG, "网络请求失败,失败原因:" + t.getMessage());
}
});
}
如果使用过OkHttp
的读者可能很熟悉最后两步创建Call
对象、发起异步网络请求的操作,几乎和OkHttp
一模一样,这是因为Retrofit
就是基于OkHttp
的啊~~
最终效果如下:
细心的读者可能发现了一个问题,在上面的代码中我是直接在CallBack
接口的onResponse()
回调方法中更新的ImageView
,即在onResponse()
中更新UI
的,在OkHttp
中这个onResponse()
方法是在子线程中被调用的,而在Retrofit
中,onResponse()
和onFailure()
这两个回调方法都是在主线程进行调用的,所以可以在其中直接更新UI
,这也是Retrofit
和OkHttp
的一点不同之处。
通过上面的例子带大家走了一遍Retrofit
的整体流程,让大家对Retrofit
有了一个整体的感知,接下来我们来逐步深入了解一下Retrofit
的具体使用。
每一个方法都必须有一个HTTP
注解,用来提供网络请求的请求方法以及相对URL
。在Retrofit
中可以使用五种请求方法:GET
,POST
,PUT
,DELETE
,HEAD
,而相对URL
直接在对应注解中填写即可,比如:
@GET("users/list")//表示以GET请求方法发起网络请求,子URL为:users/list
你可以在URL
中直接指定查询的参数:
@GET("users/list?sort=desc")
网络请求的URL
可以通过结合占位符和方法中的参数的方式来进行动态更新,所谓的占位符指的是URL
中由{}
包裹的String
类型字符串,而参数必须使用@Path
注解进行修饰,而且也只能是String
,这样,@Path
修饰的变量会动态对应到URL
中,比如:
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId);
如上面的代码所示,当代码运行的时候,groupId
会被动态绑定到子URL
中{id}
所占的位置上,达到动态设置URL
的作用。
查询参数也可以使用类似的方法进行设置:
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);
如果查询参数太多,还可以使用Map:
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);
我们可以通过@Body
注解将一个对象以 Post
方式发送给服务器:
@POST("users/new")
Call<User> createUser(@Body User user);
当我们想发送form-encoded
的数据时,可以使用@FormUrlEncode
注解,将每个键值对中的键使用@Filed
注解来进行说明,而值设置为随后跟随的对象:
@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
当我们想发送Multipart
的数据时(适用于文件发送的场景),可以使用@Multipart
注解,时使用,将每个键值对中的键使用@Part
注解来进行说明,而值设置为随后跟随的对象:
@Multipart
@PUT("user/photo")
Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);
你可以通过使用@Headers
注解为请求方法设置静态请求头:
@Headers("Cache-Control: max-age=640000")
@GET("widget/list")
Call<List<Widget>> widgetList();
或者像这样:
@Headers({
"Accept: application/vnd.github.v3.full+json",
"User-Agent: Retrofit-Sample-App"
})
@GET("users/{username}")
Call<User> getUser(@Path("username") String username);
注意,请求头中不会进行覆盖,即如果你设置两个相同键的请求头,这两个请求头都会被发送。
请求头可以使用@Header
进行动态更新,前提是设置了合法的请求头,如果你设置了类型为null
的请求头,那么对应的请求头会被忽略,如果不为null
,将最终会发送你设置参数的toString()
结果。
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)
和查询参数的设置方法类似,当请求头的参数过于复杂时,你也可以使用Map
:
@GET("user")
Call<User> getUser(@HeaderMap Map<String, String> headers)
Call
实例可以使用同步和异步两种方式进行执行,每一个实例都仅仅只能被执行一次,但是,你可以通过调用clone()
方法拷贝一份新的、同样的Call
实例,以达到多次请求的目的。
在Android
中,Call
的回调接口会在主线程中执行,在JVM
中,回调接口会在发起请求的当前线程中执行。
默认情况下,Retrofit
只能反序列化OkHttp
中的ResponseBody
类型的返回值,通过添加不同类型的转换器可以使Retrofit
拥有反序列化其他主流序列的能力,以下是一些常用转换器的列表:
Gson
:com.squareup.retrofit2:converter-gson
Jackson
:com.squareup.retrofit2:converter-jackson
Moshi
:com.squareup.retrofit2:converter-moshi
Protobuf
:com.squareup.retrofit2:converter-protobuf
Wire
:com.squareup.retrofit2:converter-wire
Simple XML
:com.squareup.retrofit2:converter-simplexml
下面是一个使用GsonConverterFactory
类反序列化GithubService
返回结果的例子:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com")
.addConverterFactory(GsonConverterFactory.create())
.build();
GitHubService service = retrofit.create(GitHubService.class);
Retrofit
支持多种网络请求适配器方式:guava
、Java8
和rxjava
使用时如使用的是 Android
默认的 CallAdapter
,则不需要添加网络请求适配器的依赖,否则则需要按照需求进行添加 Retrofit
提供的 CallAdapter
,对应依赖为:
guava
:com.squareup.retrofit2:adapter-guava:x.x.x
Java8
:com.squareup.retrofit2:adapter-java8:x.x.x
rxjava
:com.squareup.retrofit2:adapter-rxjava:x.x.x
这里使用rxjava
来发起之前例子中的网络请求:
首先修改网络请求的接口:
public interface GetRequestInterfaceWithRxJava {
/**
* 通过get()方法获取图片的请求接口
* GET注解中的参数值"2019-06-29-121904.png"和Retrofit的base url拼接在一起就是本次请求的最终地址
*
设置返回值类型为Observable的
* @return
*/
@GET("2019-06-29-121904.png")
Observable<ResponseBody> getPictureCall();
}
然后使用RxJava发起网络请求:
public void retrofitGetWithRxJava() {
/*
创建Retrofit对象,这里设置了baseUrl,注意我们在声明网络配置接口GetRequestInterface的时候在GET注解中也声明了一个Url,
我们将会这里的baseUrl和GET注解中设置的Url拼接之后就可以形成最终网络请求实际访问的url
*/
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://picture-pool.oss-cn-beijing.aliyuncs.com/").addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build();
//创建网络请求配置的接口实例
GetRequestInterfaceWithRxJava getRequestInterfaceWithRxJava = retrofit.create(GetRequestInterfaceWithRxJava.class);
//调用我们声明的getPictureCall()方法创建Call对象
Observable<ResponseBody> requestObservable = getRequestInterfaceWithRxJava.getPictureCall();
requestObservable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<ResponseBody>() {
@Override
public void onSubscribe(Disposable d) {
Log.e(TAG, "onSubscribe");
}
@Override
public void onNext(ResponseBody body) {
//将网络请求返回的数据解析为图片并展示到界面
InputStream inputStream = body.byteStream();
Drawable drawable = Drawable.createFromStream(inputStream, "pic.png");
imageView.setBackground(drawable);
Log.e(TAG, "网络请求成功");
}
@Override
public void onError(Throwable e) {
Log.e(TAG, "onError:" + e.getMessage());
}
@Override
public void onComplete() {
Log.e(TAG, "onComplete");
}
});
}
运行效果和之前的代码一样:
本文介绍了Retrofit
的基本使用和常用API
,希望可以帮大家对Retrofit
有一个入门的认识,后面我会推出有关Retrofit
源码分析等一系列文章,欢迎大家关注。