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

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} 会根据AndroidJava平台生成一个相应的网络请求的回调{@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;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值