<源码系列> Retrofit之一:用法介绍

官网: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组合规则
    Retrofit2baseUlr 必须以 /(斜线) 结束,不然会抛出一个 IllegalArgumentException
    所以如果看到别的教程没有以 / 结束,那么多半是直接从 Retrofit 1.X 照搬过来的。

一、Retrofit注解

Retrofit注解

1、@HTTP

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

2、@Path

path注解说明

3、@Header & @Headers

  • 添加请求头 &添加不固定的请求头
// @Header
@GET("user")
Call getUser(@Header("Authorization") String authorization)

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

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

  • 区别在于使用场景和使用方式
      1. 使用场景:@Header用于添加不固定的请求头,@Headers用于添加固定的请求头
      1. 使用方式:@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 是对于 CallT 的转换
    • 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 requestBodyConverter(Type type,
    Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
      return null;
    }

    // 这里用于对Field、FieldMap、Header、Path、Query、QueryMap注解的处理
    // Retrfofit对于上面的几个注解默认使用的是调用toString方法
    public Converter 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 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 stringConverter(Type type, Annotation[] annotations,
        Retrofit retrofit) {
      return null;
    }
*/

三、CallAdapter

  • 1、说明:
    • CallAdapter 则可以对 Call 转换,这样的话 Call 中的 Call 也是可以被替换的。
    • addCallAdapterFactoryaddConverterFactory 同理,也有先后顺序。
  • 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简单解析

你可能感兴趣的:(<源码系列> Retrofit之一:用法介绍)