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三步理解之三 ------------------ Retrofit完整使用分析
最新推荐文章于 2024-04-02 00:05:15 发布