retrofit2.4.0結合adapter-rxjava,converter-gson,源碼解析

retrofit2.4結合adapter-rxjava,converter-gson,源碼解析

Retrofit做爲時下android裏比較經常使用的庫,特別是結合着rxjava 後用起來非常酸爽啊,本篇就是剖析一下retrofit2.0結合adapter-rxjava,converter-gson後整個流程是怎樣串起來的,以及源碼的解析java

先看下retrofit簡介

方法類

retrofit基本使用這裏再也不贅述,直奔主題直接看源碼了

retrofit源碼地址 圖一就是今天的重點了,圖二是發起請求對應的註解種類了 android

方法類
註解類

都知道retrofit實際調用的是okhttp。也能夠說retrofi就是在okhttp的基礎上包了一層,經過大量的設計模式進行功能模塊的解耦,使得整個整個流程變得整潔和清爽、git

接口

閱讀一個三方庫 先從接口入手,先了解一下上層大體提供了哪些功能有助於快速理解github

**Call **設計模式

對於okhttp 的call的的一個再包裝,也是真正發出請求的對象接口
public interface Call<T> extends Cloneable {

  Response<T> execute() throws IOException;

  void enqueue(Callback<T> callback);

  boolean isExecuted();

  void cancel();

  Call<T> clone();

  /**返回的是okhttp的Request. */
  Request request();
}
複製代碼

**CallAdapter **api

//能夠把Call對象轉化爲另一個對象,如Observable,Flowable
public interface CallAdapter<R, T> {
    //Type  返回值泛型的對象類型如:Flowable<Response<Bean>>裏的Response<Bean>
    Type responseType();
    
   //傳入一個R返回一個T,T:返回值 一個Call或者Flowable
    T adapt(Call<R> call);
//工廠裏提供三個方法 1:根據返回值returnType獲取具體請求的CallAdapter 2:根據返回值type 獲取泛型裏的數據類型
// 3:經過type獲取class的類型,獲取整個返回值的類型  如Observable<T>,Flowable<T> ,Call<T> 
// 2,3 均爲工具類
    abstract class Factory {
//abstract抽象方法,必定要被實現
 public abstract @Nullable  CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit);
 
 protected static Type getParameterUpperBound(int index, ParameterizedType type) {
  return Utils.getParameterUpperBound(index, type);  
     
 }

 protected static Class<?> getRawType(Type type) {
 return Utils.getRawType(type);
  }
    }
}

**Callback **
請求回調
**Converter **
數據轉換適配器,能夠對請求的數據或者響應的數據再度處理
public interface Converter<F, T> {
  T convert(F value) throws IOException;

  /** Creates {@link Converter} instances based on a type and target usage. */
  abstract class Factory {
    /**
     * 傳入ResponseBody返回t,對響應數據進行解析,converter-gson會重寫此方法
     */
    public @Nullable Converter<ResponseBody, ?> responseBodyConverter(Type type,
        Annotation[] annotations, Retrofit retrofit) {
      return null;
    }

    /**
     *
     *傳入T返回ResponseBody 對請求數據進行處理,只有在 申明@Body, @Part ,@PartMap
     *這三個註解時纔會生效
     *
     */
    public @Nullable Converter<?, RequestBody> requestBodyConverter(Type type,
        Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
      return null;
    }

    /**     * 
     *  {@link Field @Field}, {@link FieldMap @FieldMap} values,
     * {@link Header @Header}, {@link HeaderMap @HeaderMap}, {@link Path @Path},
     * {@link Query @Query}, and {@link QueryMap @QueryMap} values.
     對以上註解的值進行處理 而已已經被BuiltInConverters(默認解析類)類重寫,外部重寫無效
     */
    public @Nullable Converter<?, String> stringConverter(Type type, Annotation[] annotations,
        Retrofit retrofit) {
      return null;
    }

    /**
   工具類做用與CallAdapter裏的同樣
     */
    protected static Type getParameterUpperBound(int index, ParameterizedType type) {
      return Utils.getParameterUpperBound(index, type);
    }
    
    protected static Class<?> getRawType(Type type) {
      return Utils.getRawType(type);
    }
  }
}

複製代碼

基本使用

獲取 retrofit 實例以及添加上rxjava 請求適配器和converter-gson解析器
    public Retrofit getRetrofit(String baseurl, OkHttpClient client) {
        if (client == null)
            client = getOkHttpClient();
        Retrofit.Builder builder = new Retrofit.Builder();
        builder.baseUrl(baseurl);//baseurl路徑
        builder.client(client)//添加客戶端
                .addConverterFactory(GsonConverterFactory.create());//添加Gson格式化工廠
            //添加 rxjava
            builder.addCallAdapterFactory(RxJava2CallAdapterFactory
                    .createWithScheduler(Schedulers.from(AppExecutor.instance())));
      
        retrofit = builder.build();
        return retrofit;
    }
    //自定義的通用解析類,t爲data內具體對象,msg和code爲公用數據部分
   public class Response<T> {
    private T data;
    private String msg;
    private String code;
       
   } 
//定義接口類
public interface ApiService {
     /**
     * 測試數據
     */
    @GET("data/福利/{num}/{page}")
    Flowable<Response<Bean>> getGirlList(@Path("num") int num, @Path("page") int page);   
}

//獲取ApiService
ApiService  apiservice=getRetrofit(baseurl,OkHttpClient).create(serviceClass)

//發起請求,(這裏未經封裝,正常使用要再封裝下)
apiservice.getGirlList(1,2).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribeWith(new ResourceSubscriber<Response<Bean>>() {
                @Override
                public void onNext(Response<Bean> o) {
                    //結果回調
                }

                @Override
                public void onError(Throwable t) {

                }

                @Override
                public void onComplete() {

                }
            })

複製代碼

源碼分析

Retrofit實例是使用建造者模式經過Builder類進行建立的數組

核心類
這裏只關心Android平臺下的java8的不看
    static class Android extends Platform {
        // Guarded by API check.
        @Override
        boolean isDefaultMethod(Method method) {
            if (Build.VERSION.SDK_INT < 24) {
                return false;
            }
            return method.isDefault();
        }

        @Override
        public Executor defaultCallbackExecutor() {
            return new MainThreadExecutor();
        }
        /**
         * ExecutorCallAdapterFactory默認工廠類,
         * if (getRawType(returnType) != Call.class) {
          * return null;}
          *只解析返回類型爲Call.class的數據,即原生retrofit的返回值都會使用這個工廠,緣由後面
         */
        @Override
        List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
                @Nullable Executor callbackExecutor) {
            if (callbackExecutor == null) throw new AssertionError();
            return singletonList(new ExecutorCallAdapterFactory(callbackExecutor));
        }

        /**
         * android平臺 默認爲MainThreadExecutor,
         */
        static class MainThreadExecutor implements Executor {
            private final Handler handler = new Handler(Looper.getMainLooper());

            @Override
            public void execute(Runnable r) {
                handler.post(r);
            }
        }
    }
    
**默認CallAdapter實體類 提供了只解析解析返回Call.class類型的CallAdapter **
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
  final Executor callbackExecutor;

  ExecutorCallAdapterFactory(Executor callbackExecutor) {
    this.callbackExecutor = callbackExecutor;
  }

  @Override public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
   if (getRawType(returnType) != Call.class) {
      return null;
    }
    final Type responseType = Utils.getCallResponseType(returnType);
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }


        public Retrofit build() {
            if (baseUrl == null) {
                throw new IllegalStateException("Base URL required.");
            }
            okhttp3.Call.Factory callFactory = this.callFactory;
            if (callFactory == null) {
                callFactory = new OkHttpClient();
            }
            Executor callbackExecutor = this.callbackExecutor;
            if (callbackExecutor == null) {
                //android平臺下 默認爲MainThreadExecutor,數據切換到主線程,okhttp默認是在子線程
                callbackExecutor = platform.defaultCallbackExecutor();
            }
            // Make a defensive copy of the adapters and add the default Call adapter.
            List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
            // 默認爲 ExecutorCallAdapterFactory,只解析返回類型爲Call.class的數據,即原生retrofit的返回值
            callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

            // Make a defensive copy of the converters.
            List<Converter.Factory> converterFactories = new ArrayList<>(
                    1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());

            converterFactories.add(new BuiltInConverters());//默認數據解析類 
            當返回類型爲ResponseBody時適用(即:原生okhttp)
            converterFactories.addAll(this.converterFactories);
            converterFactories.addAll(platform.defaultConverterFactories());;//defaultConverterFactories實際上什麼也沒有,默認的解析行爲都在BuiltInConverters類
            //unmodifiableList() :返回一個只能被訪問不能被修改的集合
            return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
                    unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
        }
       
複製代碼

而後看下 GsonConverterFactory gson解析類 重寫了responseBodyConverter和requestBodyConverter 實際都經過 gson 把返回數據或者請求數據解析成指定的type緩存

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;
 }

 @Override
 public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
     Retrofit retrofit) {
   TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
   return new GsonResponseBodyConverter<>(gson, adapter);
 }

 @Override
 public Converter<?, RequestBody> requestBodyConverter(Type type,
     Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
   TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
   return new GsonRequestBodyConverter<>(gson, adapter);
 }
}
複製代碼

**而後看下 RxJava2CallAdapterFactory rxjava適配器 實現get方法 只解析 返回類型爲 Observable.class ,isFlowable , isSingle ,isMaybe四類bash

public final class RxJava2CallAdapterFactory extends CallAdapter.Factory {
  /**
   * Returns an instance which creates synchronous observables that do not operate on any scheduler
   * by default.
   */
  public static RxJava2CallAdapterFactory create() {
    return new RxJava2CallAdapterFactory(null, false);
  }

  /**
   * Returns an instance which creates asynchronous observables. Applying
   * {@link Observable#subscribeOn} has no effect on stream types created by this factory.
   */
  public static RxJava2CallAdapterFactory createAsync() {
    return new RxJava2CallAdapterFactory(null, true);
  }

  /**
   * Returns an instance which creates synchronous observables that
   * {@linkplain Observable#subscribeOn(Scheduler) subscribe on} {@code scheduler} by default.
   */
  public static RxJava2CallAdapterFactory createWithScheduler(Scheduler scheduler) {
    if (scheduler == null) throw new NullPointerException("scheduler == null");
    return new RxJava2CallAdapterFactory(scheduler, false);
  }

  private final Scheduler scheduler;
  private final boolean isAsync;

  private RxJava2CallAdapterFactory(Scheduler scheduler, boolean isAsync) {
    this.scheduler = scheduler;
    this.isAsync = isAsync;
  }

  @Override
  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    Class<?> rawType = getRawType(returnType);

    if (rawType == Completable.class) {
      // Completable is not parameterized (which is what the rest of this method deals with) so it
      // can only be created with a single configuration.
      return new RxJava2CallAdapter(Void.class, scheduler, isAsync, false, true, false, false,
          false, true);
    }

    boolean isFlowable = rawType == Flowable.class;
    boolean isSingle = rawType == Single.class;
    boolean isMaybe = rawType == Maybe.class;
    if (rawType != Observable.class && !isFlowable && !isSingle && !isMaybe) {
      return null;
    }

    boolean isResult = false;
    boolean isBody = false;
    Type responseType;
    if (!(returnType instanceof ParameterizedType)) {
      String name = isFlowable ? "Flowable"
          : isSingle ? "Single"
          : isMaybe ? "Maybe" : "Observable";
      throw new IllegalStateException(name + " return type must be parameterized"
          + " as " + name + "<Foo> or " + name + "<? extends Foo>");
    }

    Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);
    Class<?> rawObservableType = getRawType(observableType);
    if (rawObservableType == Response.class) {
      if (!(observableType instanceof ParameterizedType)) {
        throw new IllegalStateException("Response must be parameterized"
            + " as Response<Foo> or Response<? extends Foo>");
      }
      responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
    } else if (rawObservableType == Result.class) {
      if (!(observableType instanceof ParameterizedType)) {
        throw new IllegalStateException("Result must be parameterized"
            + " as Result<Foo> or Result<? extends Foo>");
      }
      responseType = getParameterUpperBound(0, (ParameterizedType) observableType);
      isResult = true;
    } else {
      responseType = observableType;
      isBody = true;
    }

    return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable,
        isSingle, isMaybe, false);
  }
}
複製代碼

**繼續 Retrofit 類核心方法 **async

public <T> T create(final Class<T> service) {
        Utils.validateServiceInterface(service);//service必須爲接口類,且方法數>0
        if (validateEagerly) {//validateEagerly  是否預解析service裏全部方法註解,正常是使用一個方法才解析一個,而後放到緩存裏,下次直接用緩存
            eagerlyValidateMethods(service);
        }
        //動態代理,傳入一個接口返回一個對象
        return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[]{service},
                new InvocationHandler() {
                    private final Platform platform = Platform.get();
                    private final Object[] emptyArgs = new Object[0];

                    @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);
                        }
                        //platform.isDefaultMethod(method) 平臺下 痕爲fasle,兼容java8的不關心
                        if (platform.isDefaultMethod(method)) {
                            return platform.invokeDefaultMethod(method, service, proxy, args);
                        }
                        return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
                    }
                });
    }
    
   終於到重點  loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
複製代碼

**先看 loadServiceMethod(method) **

核心方法 result = ServiceMethod.parseAnnotations(this, method);
 
  static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);

    Type returnType = method.getGenericReturnType();
    if (Utils.hasUnresolvableType(returnType)) {
      throw methodError(method,
          "Method return type must not include a type variable or wildcard: %s", returnType);
    }
    if (returnType == void.class) {
      throw methodError(method, "Service methods cannot return void.");
    }

    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }

先看一下RequestFactory 類  經過解析註解 提供  okhttp3.Request(真正的請求)  
final class RequestFactory {
    static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
        return new Builder(retrofit, method).build();
    }
    private final Method method;  // 調用的service內方法名字
    private final HttpUrl baseUrl;
    final String httpMethod;   // 請求方法:get.post.put...
    private final String relativeUrl;//實際的url: baseUrl+ 後綴默認
    private final Headers headers;// 頭信息
    private final MediaType contentType;//contentType
    private final boolean hasBody;// post方式纔有
    private final boolean isFormEncoded;//是不是表單提交
    private final boolean isMultipart;//帶文件的鍵值對提交
    private final ParameterHandler<?>[] parameterHandlers;//這個類很重要,負責根據不一樣的註解類型 去把傳入的參數和註解的value 作相應的拼接處理
    
    
    //retrofit裏關於註解的解析 都在Builder 裏
       static final class Builder {
       Builder(Retrofit retrofit, Method method) {
            this.retrofit = retrofit;
            this.method = method;
            this.methodAnnotations = method.getAnnotations();//獲取方法上的註解
            this.parameterTypes = method.getGenericParameterTypes();//傳入參數對應的類型
            this.parameterAnnotationsArray = method.getParameterAnnotations();//參數註解,二維數組,每一個參數上的註解都是數組
        }

        RequestFactory build() {
            for (Annotation annotation : methodAnnotations) {
               //確認請求方式 並對傳入註解的value作校驗,根據請求方式肯定這次請求是否有body
                parseMethodAnnotation(annotation);
            }
               //這裏開始解析方法上的註解參數,能夠有多個參數而後 每一個參數上能夠跟多個註解,全部是個二維數組,說是這樣說,可是實際操做的時候  一個參數上只容許跟一個註解,多了會包錯
            int parameterCount = parameterAnnotationsArray.length;
            parameterHandlers = new ParameterHandler<?>[parameterCount];
            for (int p = 0; p < parameterCount; p++) {
                parameterHandlers[p] = parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p]);
            }
            return new RequestFactory(this);
        }
  }    
    }
    
複製代碼

**看下 parseParameter() **

/**
         * 解析參數註解
         *
         * @param p 當前參數的位置
         * @param parameterType 參數對應的類型
         * @param annotations   參數對應的註解,retrofit只容許有一個
         * @return
         */
        private ParameterHandler<?> parseParameter(
                int p, Type parameterType, @Nullable Annotation[] annotations) {
            ParameterHandler<?> result = null;
            if (annotations != null) {
                for (Annotation annotation : annotations) {
                    ParameterHandler<?> annotationAction =
                            parseParameterAnnotation(p, parameterType, annotations, annotation);
                    if (annotationAction == null) {
                        continue;
                    }
                    //一個參數上只容許跟一個註解 多了會拋異常
                    if (result != null) {
                        throw parameterError(method, p,
                                "Multiple Retrofit annotations found, only one allowed.");
                    }
                    result = annotationAction;
                }
            }
            if (result == null) {
                throw parameterError(method, p, "No Retrofit annotation found.");
            }

            return result;
        }
        
複製代碼

再看 parseParameterAnnotation()

相關文章
相關標籤/搜索