您的位置:首页 > 其它

Retrofit三步理解之三 ------------------ Retrofit完整使用分析

2016-02-02 10:01 323 查看
package com.mycroft.retrofitdemo;

import okhttp3.*;
import retrofit2.*;
import retrofit2.Call;
import retrofit2.http.*;
import retrofit2.http.Field;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.Arrays;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

/**
* Created by Mycroft on 2016/2/1.
*/
public class Main {

public static void main(String[] args) throws IOException {
RemoteService remoteService = RemoteService.getInstance();
String data = remoteService.getBaidu().getData();
System.out.println(data);

System.out.println(remoteService.getString().execute().body());
}
}

/**
* {@link retrofit2.Retrofit.Builder#callbackExecutor(Executor)} 的解释:
* 无论是否调用{@link retrofit2.Retrofit.Builder#addCallAdapterFactory(CallAdapter.Factory)}, {@link Retrofit}都会添加一个
* {@link CallAdapter}作为默认的。
* 如果没有使用这个方法,那{@link Retrofit} 会根据Android和Java平台生成一个相应的网络请求的回调{@link Executor},
* 在Android平台会生成一个回调在主线程中执行的{@link retrofit2.CallAdapter}, 在Java平台会生成一个默认在{@link OkHttpClient}回调池中的{@link CallAdapter}
* 而如果使用了这个方法,那么生成的默认{@link CallAdapter}的回调则会在该{@link Executor}指定的线程池中执行。
*/
class RemoteService {

private static RemoteService sRemoteService;
private final Retrofit mRetrofit;
private final IApiService mService;

public static RemoteService getInstance() {
if (sRemoteService == null) {
synchronized (RemoteService.class) {
if (sRemoteService == null) {
sRemoteService = new RemoteService();
}
}
}
return sRemoteService;
}

private final OkHttpClient mHttpClient;

private RemoteService() {
mHttpClient = new OkHttpClient.Builder().build();
mRetrofit = new Retrofit.Builder()
.client(mHttpClient)        // client()在内部会直接调用callFactory方法,即,将OkHttpClient作为默认网络请求框架,根据实际情况可以改变(几乎不会)
.callFactory(mHttpClient)   // 如上所属
.addConverterFactory(new DemoConverterAdapterFactory())        // 详看 DemoConverterAdapterFactory
.addConverterFactory(GsonConverterFactory.create())         // Retrofit自己实现的GsonConverterFactory
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())   // 详看 DemoCallAdapter
.addCallAdapterFactory((Type returnType, Annotation[] annotations, Retrofit retrofit) ->{
if ((returnType instanceof ParameterizedType) && Util.getRawType(returnType) == Encapsulation.class) {
return new DemoCallAdapter(returnType);
}
return null;
})
.callbackExecutor(Executors.newCachedThreadPool())      // 一句话不足以说明,见头部注释
.validateEagerly(true)          // 目前的理解是:当构造一个interface代理时,马上对其进行解析,而不是使用的时候再加载,加快了速度
.baseUrl("http://www.baidu.com/")   // 不解释
.build();

mService = mRetrofit.create(IApiService.class);
}

public Encapsulation<String> getBaidu() {
return mService.getBaidu();
}

public Call<String> getString(){
return mService.getString();
}
}

class Encapsulation<T> {
private final T mData;

public Encapsulation(T data) {
mData = data;
}

public T getData() {
return mData;
}
}

/**
* {@link CallAdapter}默认有两个方法:
* 1. {@link CallAdapter#responseType()} 返回此{@link CallAdapter}能够处理的数据类型
* 2. {@link CallAdapter#adapt(Call)} 将默认返回的{@link Call}转换成需要的数据类型
*
* {@link Retrofit}默认的网络请求返回类型是{@link Call}, 自然地,{@link Retrofit}有一个默认的{@link CallAdapter}
* 这个方法直接在{@link CallAdapter#adapt(Call)}中返回网络请求的结果,即{@link Call}类型。
*
* 有时(别人写好的情况下,谁没事干自己写),我们更期望另外的数据类型,例如结合RxJava使用,将其转换成{@link rx.Observable}对象,
* 那么就需要实现{@link CallAdapter}, 将{@link Call}转换为我们需要的数据类型。
*
* 如何实现{@link CallAdapter}:
* {@link retrofit2.CallAdapter.Factory#get(Type, Annotation[], Retrofit)}的参数{@link Type}参数是
* {@link CallAdapter#responseType()}的返回类型,而{@link Retrofit}要求{@link CallAdapter#responseType()}的返回类型是其中的包裹类型,
* 例如Call<String>中的{@link String}
* 概念:
* 1. {@link Retrofit}期望的是一个{@link retrofit2.CallAdapter.Factory}对象
* 2. 判断{@link retrofit2.CallAdapter.Factory#get(Type, Annotation[], Retrofit)}的参数{@link Type}是否是我们需要被转换的类型,
* 注意这里是需要将{@link Type}拆分,因为{@link Type}是一个泛型对象,传进来的类型示例:com.mycroft.retrofitdemo.Encapsulation<java.lang.String>
* 我们不会对泛型的参数类型做处理。
* 根据拆分得到的包裹类型(例如com.mycroft.retrofitdemo.Encapsulation)判断是否是我们需要的,如果是,则返回对应的{@link CallAdapter}
* 3. 实现{@link CallAdapter}: {@link CallAdapter}中有两个方法, {@link CallAdapter#responseType()}返回
*/
class DemoCallAdapter implements CallAdapter<Encapsulation<?>> {

private Type mReturnType;

public DemoCallAdapter(Type returnType) {
mReturnType = returnType;
//        System.out.println(mReturnType.getTypeName());
}

@Override
public Type responseType() {
return Util.getParameterUpperBound(0, (ParameterizedType) mReturnType);
}

@Override
public <R> Encapsulation<R> adapt(Call<R> call) {
try {
return new Encapsulation<>(call.execute().body());
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}

interface IApiService {
@GET("/")
Encapsulation<String> getBaidu();

@GET("/")
Call<String> getString();
}

/**
* 抽象类{@link retrofit2.Converter.Factory}有三个方法,分别是:
* 1. 转换网络请求结果 {@link retrofit2.Converter.Factory#responseBodyConverter(Type, Annotation[], Retrofit)}
* 2. 转换网络请求参数 {@link retrofit2.Converter.Factory#requestBodyConverter(Type, Annotation[], Retrofit)}
* 3. 转换网络请求参数 {@link retrofit2.Converter.Factory#stringConverter(Type, Annotation[])}
* <p>
* 解释:
* 1. {@link Retrofit}对{@link retrofit2.Converter.Factory}的处理:
* <code>
*     int start = converterFactories.indexOf(skipPast) + 1;
*     for (int i = start, count = converterFactories.size(); i < count; i++) {
*          Converter<?, RequestBody> converter =
*              converterFactories.get(i).requestBodyConverter(type, annotations, this);
*              if (converter != null) {
*                  //noinspection unchecked
*                  return (Converter<T, RequestBody>) converter;
*              }
*     }
*     ...
*     throw new IllegalArgumentException(builder.toString());
* </code>
* 跳过skipPast,一般而言start都是为0, 从上述代码可以看出,{@link Retrofit}是遍历所有的{@link retrofit2.Converter.Factory},
* 从中找到一个不为null的{@link Converter}并返回,如果没有找到,将抛出一个{@link IllegalArgumentException}
*
* 2. {@link Retrofit}对于{@link retrofit2.Converter.Factory#responseBodyConverter(Type, Annotation[], Retrofit)},
* {@link retrofit2.Converter.Factory#requestBodyConverter(Type, Annotation[], Retrofit)},
* {@link retrofit2.Converter.Factory#stringConverter(Type, Annotation[])}
* 的处理几乎都是一样的,除了{@link retrofit2.Converter.Factory#stringConverter(Type, Annotation[])},
* 在{@link java.util.List<retrofit2.Converter.Factory>}中寻找一个合适的{@link retrofit2.Converter.Factory},
* 返回找到的第一个{@link retrofit2.Converter.Factory}, 如果没找到,将抛出异常,
* 而{@link retrofit2.Converter.Factory#stringConverter(Type, Annotation[])} 在没找到的情况下不会抛出异常,
* 而是返回一个BuiltIn的{@link retrofit2.Converter.Factory}, 直接调用需要被转换参数的{@link Object#toString()}方法
*
* 3. {@link retrofit2.Converter.Factory#requestBodyConverter(Type, Annotation[], Retrofit)}和
* {@link retrofit2.Converter.Factory#stringConverter(Type, Annotation[])} 的区别
*
* {@link retrofit2.Converter.Factory#requestBodyConverter(Type, Annotation[], Retrofit)}处理以下注解的参数
* {@link Body @Body}, {@link Part @Part}, and {@link PartMap @PartMap}
*
* {@link retrofit2.Converter.Factory#stringConverter(Type, Annotation[])}处理以下注解的参数
* {@link Field @Field}, {@link FieldMap @FieldMap} values,
* {@link Header @Header}, {@link Path @Path}, {@link Query @Query}, and
* {@link QueryMap @QueryMap} values.
*/
class DemoConverterAdapterFactory extends Converter.Factory {

/**
* 这个方法是将ResponseBody转换为?类型,?的类型是参数{@link Type}
* 用于将网络请求的数据(以{@link ResponseBody}的形式被包裹)转换成需要的数据类型
*
* @param type        需要的数据类型,实际上就是一个Class对象
* @param annotations todo
* @param retrofit
* @return 对于参数type的一个合适的{@link Converter}对象
*/
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
System.out.println("converter: " + type.getTypeName());
if (type == String.class) {
return value -> value.string();
}
return null;
}

/**
* @param type        需要被转换的数据类型,实际上就是一个Class对象
* @param annotations
* @param retrofit
* @return 对于参数type的一个合适的{@link Converter}对象
*/
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
return super.requestBodyConverter(type, annotations, retrofit);
}

/**
* @param type        需要被转换的数据类型,实际上就是一个Class对象
* @param annotations
* @return 对于参数type的一个合适的{@link Converter}对象
*/
@Override
public Converter<?, String> stringConverter(Type type, Annotation[] annotations) {
return super.stringConverter(type, annotations);
}
}

class Util{
public static Class<?> getRawType(Type type) {
if (type instanceof Class<?>) {
// Type is a normal class.
return (Class<?>) type;

} else if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;

// I'm not exactly sure why getRawType() returns Type instead of Class. Neal isn't either but
// suspects some pathological case related to nested classes exists.
Type rawType = parameterizedType.getRawType();
if (!(rawType instanceof Class)) throw new IllegalArgumentException();
return (Class<?>) rawType;

} else if (type instanceof GenericArrayType) {
Type componentType = ((GenericArrayType) type).getGenericComponentType();
return Array.newInstance(getRawType(componentType), 0).getClass();

} else if (type instanceof TypeVariable) {
// We could use the variable's bounds, but that won't work if there are multiple. Having a raw
// type that's more general than necessary is okay.
return Object.class;

} else if (type instanceof WildcardType) {
return getRawType(((WildcardType) type).getUpperBounds()[0]);

} else {
String className = type == null ? "null" : type.getClass().getName();
throw new IllegalArgumentException("Expected a Class, ParameterizedType, or "
+ "GenericArrayType, but <" + type + "> is of type " + className);
}
}

public static Type getParameterUpperBound(int index, ParameterizedType type) {
Type[] types = type.getActualTypeArguments();
if (types.length <= index) {
throw new IllegalArgumentException(
"Expected at least " + index + " type argument(s) but got: " + Arrays.toString(types));
}
Type paramType = types[index];
if (paramType instanceof WildcardType) {
return ((WildcardType) paramType).getUpperBounds()[0];
}
return paramType;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Retrofit