表单请求
1. 普通表单
@FormUrlEncoded
:表示请求体是一个 Form 表单
Content-Type:application/x-www-form-urlencoded
采用 @Field
注解:
@FormUrlEncoded
@POST("login/login")
Call<ResponseBody> login(@Field("mail") String mail, @Field("password") String password);
采用 @FieldMap
注解:
@FormUrlEncoded
@POST("login/login")
Call<ResponseBody> login(@FieldMap Map<String, String> map);
2. Mutipart 表单
@Multipart
:表示请求体是一个支持文件上传的 Form 表单
Content-Type:multipart/form-data
@Part
注解支持的类型有:
@Part MultipartBody.Part
@Part("name") RequestBody name
@PartMap Map<String, RequestBody>
除了 okhttp3.MultipartBody.Part 之外,其他类型都必须带上表单字段,因为 okhttp3.MultipartBody.Part 中已经包含了表单字段的信息。
@Multipart
@POST("FileServlet?style=UploadFiles")
Call<ResponseBody> uploadFiles(@Part MultipartBody.Part filePart);
// @Part("name") RequestBody requestBody
上传示例:
File file = new File("D:\\test.txt");
String partName = "file";
String fileName = file.getName();
final MediaType MEDIA_OBJECT_STREAM =
MediaType.parse("application/octet-stream; charset=UTF-8");
RequestBody fileBody = RequestBody.create(MEDIA_OBJECT_STREAM, file);
MultipartBody.Part filePart = MultipartBody.Part.createFormData(partName, fileName, fileBody);
Call<ResponseBody> uploadFile = inteCastService.uploadFiles(filePart);
GET 方式请求 JSON 数据并解析得到 GSON 对象
// Repo 是由 Android Studio 插件 GsonFormat 从 JSON 字符串自动生成的类
interface GithubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
private void connect() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
GithubService githubService = retrofit.create(GithubService.class);
Call<List<Repo>> octocat = githubService.listRepos("xiangaoole");
octocat.enqueue(mCallback);
}
private Callback<List<Repo>> mCallback = new Callback<List<Repo>>() {
@Override
public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
List<Repo> body = response.body();
for (int i = 0; i < body.size(); i++) {
Repo repo = body.get(i);
System.out.println(repo.getName());
}
}
@Override
public void onFailure(Call<List<Repo>> call, Throwable t) {
}
};
自定义 Converter
Converter 类的作用是从 HTTP 响应体中解析生成特定类型的对象,反之亦然。
public interface Converter<F, T> {
// 实现从 F(rom)到 T(o)的转换
T convert(F value) throws IOException;
// 提供 Converter 的工厂类
abstract class Factory {
// 返回一个将 HTTP 响应体解析为 type 类型对象的 Converter。
public @Nullable Converter<ResponseBody, ?> responseBodyConverter(Type type,
Annotation[] annotations, Retrofit retrofit) {
return null;
}
// 返回一个将 type 类型对象转化为 HTTP 请求体的 Converter。
public @Nullable Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return null;
}
// 返回一个将 type 类型对象转化为 String 的 Converter。
public @Nullable Converter<?, String> stringConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return null;
}
// 提取出 type 类型中第 index 个参数的泛型上界
// 比如 Map<String, ? extends Runnable> 的第 1 个参数的泛型上界是 Runnable
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
// 提取出 type 类型的原始类
// 比如 List<? extends Runnable> 返回 List.class
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
}
- responseBodyConverter :主要用于处理响应体
- requestBodyConverter :主要用于处理 Part、PartMap、Body 注解
- stringConverter :主要用于处理 Field、FieldMap、Header、Path、Query、QueryMap 注解(默认调用 toString 方法)
下面我们演示一个自定义 ResponseBody 到 String 的自定义 Converter。
第一步:实现 Converter
public class StringConverter implements Converter<ResponseBody, String> {
public static final StringConverter INSTANCE = new StringConverter();
@Override
public String convert(@Nullable ResponseBody value) throws IOException {
return value != null ? value.string() : null;
}
}
第二步:创建 Converter.Factory 子类
我们通过 Factory 的 create 方法来获得 Factory 实例,因为我们只处理 Call ,所以只用重写 responseBodyConverter 方法。
public static class StringConverterFactory extends Converter.Factory {
public static final StringConverterFactory INSTANCE = new StringConverterFactory();
public static StringConverterFactory create() {
return INSTANCE;
}
@Nullable
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
if (type == String.class)
return StringConverter.INSTANCE;
else
return null;
}
}
第三步:注册 Converter.Factory
addConverterFactory 是有先后顺序的,如果有多个 ConverterFactory 都支持同一种类型,那么只有第一个才会被使用。但是要注意的是, GsonConverterFactory 支持所有类型,所以要放在最后。
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://localhost:8080/InteCAST/")
.addConverterFactory(StringConverter.StringConverterFactory.create())
.build();
自定义 CallAdapter
Converter 的作用是将 Call 转化为 Call,而CallAdapter 则可以将 Call 转化为其他类型。比如在 Retrofit 中使用 RxJava 时,可以将 Call 转化为 Observable,只需要向 Retrofit 中注册相应的 CallAdapterFactory。
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://localhost:8080/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
// 针对rxjava2.x
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
CallAdapter 接口的定义如下:
public interface CallAdapter<R, T> {
// 返回将 Call<Repo> 中的 Repo
// 这个 T 会作为 Converter.Factory.responseBodyConverter 的第一个参数
Type responseType();
// 返回 Call<R> 的委托实例 T
/* 比如下面的方法将 Call<R> 转化为 Async<R>对象,可以调用 call 方法来执行
@Override
public <R> Async<R> adapt(final Call<R> call) {
return Async.create(new Callable<Response<R>>() {
@Override
public Response<R> call() throws Exception {
return call.execute();
}
});
}
*/
T adapt(Call<R> call);
// 提供 CallAdapter 的工厂类
abstract class Factory {
// 返回一个能返回 returnType 的 CallAdapter
public abstract @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
Retrofit retrofit);
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
}
下面演示自定义一个 MyCallAdapter 将 Call 转化为 MyCall。
第一步:定义 MyCall
这里的 MyCall 采用代理模式,封装了一个 Call 实例,提供一个同步获取数据的 get 方法。
public class MyCall<R> {
public final Call<R> call;
public MyCall(Call<R> call) {
this.call = call;
}
public R get() throws IOException {
return call.execute().body();
}
}
第二步:实现 CallAdapter
public class MyCallAdapter implements CallAdapter<R, MyCall<R>> {
private final Type responseType;
MyCallAdapter(Type responseType) {
this.responseType = responseType;
}
@Override
public Type responseType() {
return responseType;
}
@Override
public MyCall<R> adapt(Call<R> call) {
return new MyCall<>(call);
}
}
第三步:定义 CallAdapter.Factory 子类
重写 get 方法,MyCall 的 raw type 为 MyCall.class,类型匹配之后,getParameterUpperBound 得到 Call 的第 0 个参数的泛型上界是 String,然后新建 MyCallAdapter 返回。
public class MyCallAdapter implements CallAdapter<R, MyCall<R>> {
...
public static class Factory extends CallAdapter.Factory {
public static final Factory INSTANCE = new Factory();
@Nullable
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
Class<?> rawType = getRawType(returnType);
if (rawType == MyCall.class && returnType instanceof ParameterizedType) {
Type callReturnType = getParameterUpperBound(0, (ParameterizedType) returnType);
return new MyCallAdapter(callReturnType);
}
return null;
}
}
}
最后一步:注册 CallAdapter.Factory
这里接着自定义 StringConverter 的内容,我们实现了 Call -> Call -> MyCall 的转化。
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://localhost:8080/InteCAST/")
.addConverterFactory(StringConverter.StringConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(MyCallAdapter.Factory.INSTANCE)
.build();
Retrofit 中 Url 组合规则
baseUrl | 和 url 有关的注解中的值 | 最终结果 |
---|---|---|
http://localhost:8080/path/ |
/post |
http://localhost:8080/post |
http://localhost:8080/path/ |
post |
http://localhost:8080/path/post |
http://localhost:8080/path/ |
http://baidu.com/ |
http://baidu.com/ |
从上面可以看出如下规则:
- 注解中 url 为完整的 url,则以此为最终的 url
- 注解中 url 不完整,且以
/
开头,则最终请求的 url 为 baseUrl 的主机部分 + 有关的注解中的值 - 注解中 url 不完整,且不以
/
开头,则最终请求的 url 为 baseUrl + 有关的注解中的值