总结:Retrofit的使用

Retrofit,一个RESTful( *无状态* )的HTTP网络请求框架(基于OkHttp)( *封装* )


官网https://square.github.io/retrofit/

简介:

  • Retrofit,一个RESTful( 无状态 )的HTTP网络请求框架(基于OkHttp)( 封装 )
  • 注解配置网络请求参数,解耦彻底,扩展性强
    交互示意图

示例

  • 集成

    1
    2
    3
    4
    5
    //build.gradle 引入
    implementation 'com.squareup.retrofit2:retrofit:(insert latest version)'

    //AndroidManifest.xml 中添加权限
    <uses-permission android:name="android.permission.INTERNET"/>
  • 使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    //① 创建Java接口
    public interface GitHubService {
    @GET("users/{user}/repos")
    Call<List<Repo>> 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<List<Repo>> repos = service.listRepos("octocat");

    call.enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
    try {
    System.out.println(response.body().string());
    } catch (IOException e) {
    e.printStackTrace();
    }
    }

    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {
    t.printStackTrace();
    }
    });

注意:

  • 1、Retrofit的Url组合规则
    Retrofit2baseUlr 必须以 /(斜线) 结束,不然会抛出一个 IllegalArgumentException
    所以如果看到别的教程没有以 / 结束,那么多半是直接从 Retrofit 1.X 照搬过来的。

一、Retrofit注解

Retrofit注解

1、@HTTP

  • 有三个属性:methodpathhasBody

    1
    2
    3
    4
    5
    6
    7
    /**
    * method 表示请求的方法,区分大小写
    * path表示路径
    * hasBody表示是否有请求体
    */
    @HTTP(method = "GET", path = "blog/{id}", hasBody = false)
    Call<ResponseBody> getBlog(@Path("id") int id);
  • 注: method 的值 retrofit 不会做处理,所以要自行保证其准确性,

2、@Path

path注解说明

3、@Header & @Headers

  • 添加请求头 &添加不固定的请求头
    1
    2
    3
    4
    5
    6
    7
    8
    // @Header
    @GET("user")
    Call<User> getUser(@Header("Authorization") String authorization)

    // @Headers
    @Headers("Authorization: authorization")
    @GET("user")
    Call<User> getUser()

说明:
以上的效果是一致的。

  • 区别在于使用场景和使用方式
      1. 使用场景:@Header用于添加不固定的请求头,@Headers用于添加固定的请求头
        1. 使用方式:@Header作用于方法的参数;@Headers作用于方法

4、@Body

  • @Body 的参数如果是一个Map ,则作用相当于@Field
    不过Map要经过 FormBody.Builder 类处理成为符合 Okhttp 格式的表单,如:
    1
    2
    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>T 的转换
    • addConverterFactory 是有先后顺序的,如果有多个 ConverterFactory 都支持同一种类型,那么就是只有第一个才会被使用,而 GsonConverterFactory 是不判断是否支持的,所以这里交换了顺序还会有一个异常抛出,原因是类型不匹配。
  • 3、使用:

    1
    2
    3
    4
    5
    6
    Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("http://localhost:4567/")
    // 我们自定义的一定要放在Gson这类的Converter前面
    .addConverterFactory(StringConverterFactory.create())
    .addConverterFactory(GsonConverterFactory.create())
    .build();
  • 4、Converter 源码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    public interface Converter<F, T> {
    // 实现从 F(rom) 到 T(o)的转换
    T convert(F value) throws IOException;

    // 用于向Retrofit提供相应Converter的工厂
    abstract class Factory {
    // 这里创建从ResponseBody其它类型的Converter,如果不能处理返回null
    // 主要用于对响应体的处理
    public Converter<ResponseBody, ?> 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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    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<ResponseBody, ?> 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<T> 中的 Call 也是可以被替换的。
    • addCallAdapterFactoryaddConverterFactory 同理,也有先后顺序。
  • 2、使用:
    1
    2
    //引入RxJava2支持:
    compile 'com.squareup.retrofit2:adapter-rxjava:2.6.1'

注:以上版本可能不是最新版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//通过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<Result<List<Blog>>> getBlogs();
}

//使用:
BlogService service = retrofit.create(BlogService.class);
service.getBlogs(1)
.subscribeOn(Schedulers.io())
.subscribe(new Subscriber<Result<List<Blog>>>() {
@Override
public void onCompleted() {
System.out.println("onCompleted");
}

@Override
public void onError(Throwable e) {
System.err.println("onError");
}

@Override
public void onNext(Result<List<Blog>> blogsResult) {
System.out.println(blogsResult);
}
});
  • 3、CallAdapter源码:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    public interface CallAdapter<T> {

    // 直正数据的类型 如Call<T> 中的 T
    // 这个 T 会作为Converter.Factory.responseBodyConverter 的第一个参数
    // 可以参照上面的自定义Converter
    Type responseType();

    <R> T adapt(Call<R> call);

    // 用于向Retrofit提供CallAdapter的工厂类
    abstract class Factory {
    // 在这个方法中判断是否是我们支持的类型,returnType 即Call<Requestbody>和`Observable<Requestbody>`
    // RxJavaCallAdapterFactory 就是判断returnType是不是Observable<?> 类型
    // 不支持时返回null
    public abstract CallAdapter<?> get(Type returnType, Annotation[] annotations,
    Retrofit retrofit);

    // 用于获取泛型的参数 如 Call<Requestbody> 中 Requestbody
    protected static Type getParameterUpperBound(int index, ParameterizedType type) {
    return Utils.getParameterUpperBound(index, type);
    }

    // 用于获取泛型的原始类型 如 Call<Requestbody> 中的 Call
    // 上面的get方法需要使用该方法。
    protected static Class<?> getRawType(Type type) {
    return Utils.getRawType(type);
    }
    }
    }

四、相关链接:

Retrofit 2.0 使用教程

Retrofit2详解

你真的会用Retrofit2吗?Retrofit2完全教程

Retrofit2源码解析

Retrofit之Converter简单解析

-------------我是有底线的-------------