官网:https://square.github.io/retrofit/
简介:
- Retrofit,一个RESTful( 无状态 )的HTTP网络请求框架(基于OkHttp)( 封装 )
-
注解配置网络请求参数,解耦彻底,扩展性强
示例:
- 集成
//build.gradle 引入
implementation 'com.squareup.retrofit2:retrofit:(insert latest version)'
//AndroidManifest.xml 中添加权限
- 使用
//① 创建Java接口
public interface GitHubService {
@GET("users/{user}/repos")
Call> listRepos(@Path("user") String user);
}
//② Retrofit实现创建的Java接口
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create()) // 设置数据解析器
.addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // 支持RxJava平台
.build();
GitHubService service = retrofit.create(GitHubService.class);
//③调用(同步或异步选其一)
Call> repos = service.listRepos("octocat");
//同步请求
Response res = repos.execute();
//或异步请求
repos.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
try {
System.out.println(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onFailure(Call call, Throwable t) {
t.printStackTrace();
}
});
注意:
- 1、Retrofit的Url组合规则
Retrofit2
的baseUlr
必须以/
(斜线) 结束,不然会抛出一个IllegalArgumentException
。
所以如果看到别的教程没有以/
结束,那么多半是直接从Retrofit 1.X
照搬过来的。
一、Retrofit注解
1、@HTTP
- 有三个属性:
method
、path
、hasBody
/**
* method 表示请求的方法,区分大小写
* path表示路径
* hasBody表示是否有请求体
*/
@HTTP(method = "GET", path = "blog/{id}", hasBody = false)
Call getBlog(@Path("id") int id);
- 注:
method
的值retrofit
不会做处理,所以要自行保证其准确性,
2、@Path
3、@Header & @Headers
- 添加请求头 &添加不固定的请求头
// @Header
@GET("user")
Call getUser(@Header("Authorization") String authorization)
// @Headers
@Headers("Authorization: authorization")
@GET("user")
Call getUser()
说明:
以上的效果是一致的。
- 区别在于使用场景和使用方式
-
- 使用场景:@Header用于添加不固定的请求头,@Headers用于添加固定的请求头
-
- 使用方式:@Header作用于方法的参数;@Headers作用于方法
-
4、@Body
-
@Body
的参数如果是一个Map
,则作用相当于@Field
不过Map要经过 FormBody.Builder 类处理成为符合 Okhttp 格式的表单,如:
FormBody.Builder builder = new FormBody.Builder();
builder.add("key","value");
5、@Field & @FieldMap;@Part & @PartMap
-
@Field
与@FieldMap
配合使用,在发送Post
请求时提交请求的表单字段 -
@Part
与@Field
的区别:功能相同,但携带的参数类型更加丰富,包括数据流,所以适用于 有文件上传 的场景
6、@Query和@QueryMap
- 用于 @GET 方法的查询参数(Query 相当于 Url 中 ‘?’ 后面的 key-value)
二、Converter
-
1、Retrofit支持多种数据解析方式
注:以上版本可能不是最新版本 -
2、说明:
-
Convert.Factoy
的具体作用就是获取一个Convert
-
Converter
是对于Call
中T
的转换 -
addConverterFactory
是有先后顺序的,如果有多个ConverterFactory
都支持同一种类型,那么就是只有第一个才会被使用,而GsonConverterFactory
是不判断是否支持的,所以这里交换了顺序还会有一个异常抛出,原因是类型不匹配。
-
3、使用:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://localhost:4567/")
// 我们自定义的一定要放在Gson这类的Converter前面
.addConverterFactory(StringConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
- 4、
Converter
源码
public interface Converter {
// 实现从 F(rom) 到 T(o)的转换
T convert(F value) throws IOException;
// 用于向Retrofit提供相应Converter的工厂
abstract class Factory {
// 这里创建从ResponseBody其它类型的Converter,如果不能处理返回null
// 主要用于对响应体的处理
public Converter responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return null;
}
// 在这里创建 从自定类型到ResponseBody 的Converter,不能处理就返回null,
// 主要用于对Part、PartMap、Body注解的处理
public Converter, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return null;
}
// 这里用于对Field、FieldMap、Header、Path、Query、QueryMap注解的处理
// Retrfofit对于上面的几个注解默认使用的是调用toString方法
public Converter, String> stringConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return null;
}
}
}
- 5、定义Gson的Converter
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.reflect.TypeToken;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Converter;
import retrofit2.Retrofit;
public final class GsonConverterFactory extends Converter.Factory {
/**
* Create an instance using a default {@link Gson} instance for conversion. Encoding to JSON and
* decoding from JSON (when no charset is specified by a header) will use UTF-8.
*/
public static GsonConverterFactory create() {
return create(new Gson());
}
/**
* Create an instance using {@code gson} for conversion. Encoding to JSON and
* decoding from JSON (when no charset is specified by a header) will use UTF-8.
*/
public static GsonConverterFactory create(Gson gson) {
return new GsonConverterFactory(gson);
}
private final Gson gson;
private GsonConverterFactory(Gson gson) {
if (gson == null) throw new NullPointerException("gson == null");
this.gson = gson;
}
//对ResponseBody进行数据转换的转换器
@Override
public Converter responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
TypeAdapter> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonResponseBodyConverter<>(gson, adapter);
}
//将未知数据转换成RequestBody的转换器
@Override
public Converter, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
TypeAdapter> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonRequestBodyConverter<>(gson, adapter);
}
}
/*
//Converter.Factory中的方法
//将未知数据转换成String类型的数据转换器
public @Nullable Converter, String> stringConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return null;
}
*/
三、CallAdapter
- 1、说明:
-
CallAdapter
则可以对Call
转换,这样的话Call
中的Call
也是可以被替换的。 -
addCallAdapterFactory
与addConverterFactory
同理,也有先后顺序。
-
- 2、使用:
//引入RxJava2支持:
compile 'com.squareup.retrofit2:adapter-rxjava:2.6.1'
注:以上版本可能不是最新版本
//通过RxJavaCallAdapterFactory为Retrofit添加RxJava支持:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://localhost:4567/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
// 针对rxjava2.x
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
//接口设计
public interface BlogService {
@POST("/blog")
Observable>> getBlogs();
}
//使用:
BlogService service = retrofit.create(BlogService.class);
service.getBlogs(1)
.subscribeOn(Schedulers.io())
.subscribe(new Subscriber>>() {
@Override
public void onCompleted() {
System.out.println("onCompleted");
}
@Override
public void onError(Throwable e) {
System.err.println("onError");
}
@Override
public void onNext(Result> blogsResult) {
System.out.println(blogsResult);
}
});
- 3、CallAdapter源码:
public interface CallAdapter {
// 直正数据的类型 如Call 中的 T
// 这个 T 会作为Converter.Factory.responseBodyConverter 的第一个参数
// 可以参照上面的自定义Converter
Type responseType();
T adapt(Call call);
// 用于向Retrofit提供CallAdapter的工厂类
abstract class Factory {
// 在这个方法中判断是否是我们支持的类型,returnType 即Call和`Observable`
// RxJavaCallAdapterFactory 就是判断returnType是不是Observable> 类型
// 不支持时返回null
public abstract CallAdapter> get(Type returnType, Annotation[] annotations,
Retrofit retrofit);
// 用于获取泛型的参数 如 Call 中 Requestbody
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
// 用于获取泛型的原始类型 如 Call 中的 Call
// 上面的get方法需要使用该方法。
protected static Class> getRawType(Type type) {
return Utils.getRawType(type);
}
}
}
四、相关链接:
Retrofit 2.0 使用教程
Retrofit2详解
你真的会用Retrofit2吗?Retrofit2完全教程
Retrofit2源码解析
Retrofit之Converter简单解析