Retrofit2 使用及浅析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/MrJarvisDong/article/details/81208013

Retrofit 2

retrofit2


使用方法

retrofit java interface 配置:

  使用注解描述http请求:
  替代URL的参数路径, 查询参数支持;
  对象转变成请求体;
  Multipart请求体和文件上传;

  eg:
  public interface MyApi {
  @GET("users/{user}/repos")
  Call<User> getUser()(@Path("user") String user);
}

Retrofit retrofit = new Retrofit.Builder()
      .baseUrl("https://api.example.com/")
      .addConverterFactory(GsonConverterFactory.create()))
      .build();

MyApi api = retrofit.create(MyApi.class);
Response<User> user = api.getUser().execute();

常用Api解析

请求方法

每个方法必须有Http注解,由请求方法和相关URL提供;有5个内置注解:
GET,POST,PUT,DELETE,HEAD;注解中指定相关的URL资源;url上也可指定查询参数 eg:

@GET("users/list?sort=desc")

URL操作

请求的URl可以动态的使用替代块和方法参数去更新,{}中即是替代块,对应于@Path中的参数,参数可用@Query,复杂参数可使用@QueryMap; eg:

@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") sort, [或者]@QueryMap Map<String, String> options);

请求体

使用@Body注解 可以指定一个对象使用哪种请求体;
Retrofit对象中,也可指定一个对象使用converter转换;没有converter,只有RequestBody被使用;

@POST("users/new")
Call<User> createUser(@Body User user);

Encoded编码 & Multipart

使用form-encoded 和multipart数据 可以声明方法;
@FormUrlEncoded出现在方法上,代表form表单需要被encoded编码,每个key-value对需要被@Field注解;
@Multipart 使用在方法上,代表multipart 文件请求,使用@Part注解声明Parts 文件;
multipart parts 使用Retrofit Converters转换器或者implement RequestBody 处理序列化;

@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);

@Multipart
@PUT("user/photo")
Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);

请求头处理

@Headers 注解方法设置静态的头信息;key-value;
请求头可以被@Header 动态的更新,相关的参数可以被@Header提供.value是null时,header将会被忽略;不为null时,value就是toString方法的值;
可以使用@HeaderMap处理复杂的头信息组成;

需要对每个请求添加头信息,使用拦截器;

@Headers({
    "Accept: application/vnd.github.v3.full+json",
    "User-Agent: Retrofit-Sample-App"
})
@GET("users/{username}")
Call<User> getUser(@Path("username") String username);

@GET("user")
Call<User> getUser(@Header("Authorization") String authorization, [或者]@HeaderMap Map<String, String> headers)

异步 & 同步

Call对象代表http请求,可以被同步执行,也可以被异步执行;每个对象仅仅只会被使用一次,使用过的对象可以调clone()方法复制一个新的可用对象;


Retrofit 常见配置

通过Retrofit类可以将你的Api接口转换成回调对象;

Converters转换器

默认情况下,Retrofit仅仅将http 体 反序列化成ResponseBody类型(call的通用参数为response body类型),也只能接受@Body的RequestBody类型;

可以使用Converter.Factory实例转换响应体,如果不关心内容可以使用Void类型;

Converter 支持其他类型:

    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
    Scalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars

//使用GsonConverterFactory 转换器进行反序列化;
Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com")
    .addConverterFactory(GsonConverterFactory.create())
    .build();
//生成retrofit接口的实现类;
GitHubService service = retrofit.create(GitHubService.class);

自定义converter

建造一个继承Converter.Factory类,通过对象构造自定的适配器;

@注解
- GET
- PUT
- POST
- PATCH
- HEAD
- DELETE
- OPTIONS
- HTTP 自定义

@Url:方法参数,可以操作动态的Url,忽略注解中的路径并且在第一个参数中使用Url注解;

@POST()
    Call<BaseBean<LogBean>> getLogBeanDynamic(
            @Url() String url,
            @Query("mobile") String mobile,
            @Query("password") String password);

@Path:方法参数,替换Url的一部分;被替换的部分使用{foo}花括号所表示;

@Query:方法参数,添加到Url的查询参数;

@Body:方法参数,表示请求体,被Converter.Factory的对象所转换; RequestBody可被用于raw repersentation;

更改请求体格式:

@FormUrlEncoded:所有被@Field注解的参数,都会被encode编码成 Form-encoded 的键值对;

@MultiPart:所有被@Part注解的参数,都会被指定为 兼容的multipart data >parts;


Retrofit2 源码浅析

Retrofit

该类为了动态代理 by create(改建)一个用于http调用的java 接口,为了使用声明方法上的注解去定义如何请求; 使用create (Builder)方法生成一个动态代理实现类;

//有关属性
private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
//网络工厂,一般实现是OkHttpClient;
final okhttp3.Call.Factory callFactory; 
final HttpUrl baseUrl;
//转换ResponseBody数据,如GsonConverter;
final List<Converter.Factory> converterFactories;
//返回值的再次封装处理,原始Call对象,可以扩展为RxJavaAdapter;
final List<CallAdapter.Factory> adapterFactories;
//线程池
final @Nullable Executor callbackExecutor;
//是否迫切更新;
final boolean validateEagerly;


//动态代理自定义的http调用接口类
public <T> T create(final Class<T> service) {
//判断是否符合条件,必须是接口,并且接口方法的数量>0
    Utils.validateServiceInterface(service);
    //是否需要迫切更新配置中所有方法;
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    //返回retrofit 定义接口的动态代理对象(AOP)
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();

          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
            // If the method is a method from Object then defer to normal invocation.
            //对象的方法直接使用调用,不增强;
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            //缓存封装方法及请求参数的对象 ServiceMethods;
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            //执行掉用请求的Call对象;
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            //使用转换Call对象的适配器,如retrofit 接口方法返回值为Observable,即 使用的是Rxjava的适配器;
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

Builder:
Retrofit的构造类

可指定
OkHttpClient(Call.Factory ),
BaseUrl,
Converter.Factory,
Executor;

设置BaseUrl注意::baseurl 应该必须以 / 结尾;

eg:
1. 端点的值不包含 / 代表相对路径,将把有path components的路径拼接到BaseUrl上;
Base URL: http://example.com/api/<br>
Endpoint: foo/bar/<br>
Result: http://example.com/api/foo/bar/

 <b>Incorrect:</b><br>不以/结尾会强制找到/结尾;
Base URL: http://example.com/api<br>
Endpoint: foo/bar/<br>
Result: http://example.com/foo/bar/

2. 端点的值包含 / 代表是绝对路径,结果仅保留baseUrl的Host ,忽略特殊的路径组件;
Base URL: http://example.com/api/<br>
Endpoint: /foo/bar/<br>
Result: http://example.com/foo/bar/

Base URL: http://example.com/<br>
Endpoint: /foo/bar/<br>
Result: http://example.com/foo/bar/

3. 端点值是一个Url全路径,结果是端点的host代替baseUrl的host,并且值的约束也代替BaseUrl的约束;
Base URL: http://example.com/<br>
Endpoint: https://github.com/square/retrofit/<br>
Result: https://github.com/square/retrofit/

Base URL: http://example.com<br>
Endpoint: //github.com/square/retrofit/<br>
Result: http://github.com/square/retrofit/ (note the scheme stays 'http')

ServiceMethod

可以在一个http调用中进行invocation(即实现对接口的动态代理);
缓存的 retrofit接口类 方法及方法注解及需要的请求参数等;
对注解进行解析,对每个接口中的方法进行处理,即进行动态代理的方法增强;

返回值的处理扩展:

内部通过方法addCallAdapterFactory添加的工厂创建 CallAdapter.Factory,没有设置则使用默认的工厂,默认由PlatForm提供;

可以添加扩展RxJavaAdapter;

数据的转换处理:

通过方法addConverterFactory添加工厂创建Converter.Factory,默认添加了BuiltInConverters

可以添加扩展GsonConverter;

OkHttpCall

retrofit的Call请求具体实现;
本身继承于retrofit2.Call,内部通过okhttp3.Call调取网络;
okhttp3.Call的对象由createRawCall方法构建;

okhttp3的联网处理:

newCall方法由okhttp3.Call.Factory工厂构建okhttp3.Call对象,实现类callFactory 即构建Retrofit传入的OkHttpClient工厂对象,newCall的具体实现在OkHttpClient中;

OkHttpClient工厂具体构建的类是RealCall类;
RealCall implements okhttp3.Call是真正调取接口的实现;

//OkhttpCall中
private okhttp3.Call createRawCall() throws IOException {
//将retrofit接口中方法的参数转换成Request对象;
    Request request = serviceMethod.toRequest(args);
 //通过传入的`callFactory`(一般即OkHttpClient对象)构建
 //`okhttp3.Call`对象(一般为RealCall对象)
   okhttp3.Call call =  serviceMethod.callFactory.newCall(request);
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }


//Retrofit中
public Builder client(OkHttpClient client) {
      return callFactory(checkNotNull(client, "client == null"));
    }


public Builder callFactory(okhttp3.Call.Factory    factory) {
      this.callFactory = checkNotNull(factory, "factory == null");
        return this;
}

/** OkHttpClient中
   * Prepares the {@code request} to be executed at some point in the future.
   */
  @Override 
  public Call newCall(Request request) {
    return new RealCall(this, request, false /* for web socket */);
  }

Platform

判断anroid平台还是java8平台,动态代理中没有使用,构造链中设置默认值使用,设置ExecutorCallAdapter.Factory默认值;


Retrofit2:converter-gson Gson格式转换器

GsonConverterFactory,自定义的Gson Converter.Factory
重写工厂方法responseBodyConverter && requestBodyConverter;

addConverterFactory(Converter.Factory)添加至Retrofit的对象中;

GsonRequestBodyConverter (implement Converter< T, RequestBody>)

使用Gson的TypeAdapters(type adapter for basic types)处理,找到处理目标Type的TypeAdapter;重写抽象方法convert

@Override public RequestBody convert(T value) throws IOException {
//创建流,将value写入到typeAdapter
    Buffer buffer = new Buffer();
    Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
    JsonWriter jsonWriter = gson.newJsonWriter(writer);
    adapter.write(jsonWriter, value);
    jsonWriter.close();
    return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
  }

GsonResponseBodyConverter

同上,处理响应数据,OkHttpCall将rawResponse - > Response ,回调出去;

@Override public T convert(ResponseBody value) throws IOException {
    JsonReader jsonReader = gson.newJsonReader(value.charStream());
    try {
      return adapter.read(jsonReader);
    } finally {
      value.close();
    }
  }

TypeAdapter

gson中用于Java objects 和Json的相互转换;
可继承该类实现自定义的转换;
read(JsonReader)

必须精确读一个值,常用方法 nextBoolean(),nextDouble(),nextInt(),nextLong(),nextString(),nextNull();

write(JsonWrite,Object)

必须精确的写一个值,常用方法
value(),nullValue();

对于数组,类型适配器先开始调用beginArray()转化所有的元素,结束时调用endArray();对于对象,开始时调用beginObject,转换对象,结束时使用endObject();

使用nullSafe()方法注册类型适配器,如果Gson instance已经配置了 GsonBuilder serializeNulls(),空值将被写于最终的文档中;否则 value 将被自动忽略(这种情况下,typeadapter 必须处理空值);

eg: Gson 转换 Point <-> JSON "5","8"
public class PointAdapter extends TypeAdapter<Point> {
 *     public Point read(JsonReader reader) throws IOException {
 *       if (reader.peek() == JsonToken.NULL) {
 *         reader.nextNull();
 *         return null;
 *       }
 *       String xy = reader.nextString();
 *       String[] parts = xy.split(",");
 *       int x = Integer.parseInt(parts[0]);
 *       int y = Integer.parseInt(parts[1]);
 *       return new Point(x, y);
 *     }
 *     public void write(JsonWriter writer, Point value) throws IOException {
 *       if (value == null) {
 *         writer.nullValue();
 *         return;
 *       }
 *       String xy = value.getX() + "," + value.getY();
 *       writer.value(xy);
 *     }
 *   }}</pre>
 *

使用自定义的type adapter 必须使用GsonBuilder注册

GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Point.class, new PointAdapter());
// if PointAdapter didn't check for nulls in its read/write methods, you should instead use
// builder.registerTypeAdapter(Point.class, new PointAdapter().nullSafe());
...
Gson gson = builder.create();    

Retrofit2:adatpter-rxjava Rxjava适配器;

RxJava2CallAdapterFactory,自定义的CallAdapter.Factory工厂,对返回值Call对象再次处理;

addCallAdapterFactory(CallAdapter.Factory)添加至Retrofit的对象中;

使用RxJava2创建Observable,添加当前工厂,允许从service 方法返回
Observable,Flowable,
Single,Completable,
Maybe对象,代替Call对象;

  1. Observable< User> :onNext-> 反序列化数据返回 响应码2XX响应;
    onError->HttpException 返回 非2XX的响应,网络错误返回IoException;

  2. Observable< Response< User>> : onNext -> 所有Http responses的Response对象;onError -> 网络错误IoException

  3. Observable< Result< User>> : onNext->所有的Http responses和error 的Result对象;

retrofit2.CallAdapter $ Factory

[动态代理]改造返回值Call的响应类型;

1.抽象方法 Type responseType();

此adapter使用 转换Http response body 成java对象的返回类型;eg:
Call -> Repo ;

2.抽象方法 T adapt(Call call);

返回call的代理对象;

CallAdapter.Factory工厂类的抽象方法

//返回一个接口方法返回类型的call adapter 
public abstract @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
        Retrofit retrofit);

//提取通用类型的上限, Map<String, ? extends Runnable>
//index 1 -> Runnable
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
      return Utils.getParameterUpperBound(index, type);
    }
//提起raw class type,List<? extends Runnable> 
//->List.class    
protected static Class<?> getRawType(Type type) {
      return Utils.getRawType(type);
    }

RxJava2CallAdapter

Rxjava的包,CallAdapter.Factory get抽象方法返回的CallAdapter;

responseType() 获取的返回类型的上限;

adapt()代理call对象
(分为返回值< R>,< Response< R>>,< Result< R>>):

1.<Result<R>>:
封装< Response< R>>

ResultObservable(extends Observable< Result< T>>)
使用RxJava特点->
ResultObservable.ResultObserver(implements Observer< Response< R>>)->
onNext中使用Result的方法将Response转成Result;

2.<R>:
封装< Response< R>>

BodyObservable(extends Observable< T>)
使用RxJava特点->
BodyObservable.BodyObserver(implements Observer< Response< R>>) -> onNextresponse.body()

3.<Response<R>>:

异步 CallEnqueueObservable(extends Observable< Response< T>>);

同步 CallExecuteObservable(extends Observable< Response< T>>)

最后使用RxJava的订阅-发布;

详细见RxJava章节

猜你喜欢

转载自blog.csdn.net/MrJarvisDong/article/details/81208013