retrofit2+rxjava+mockserver使用和理解

来源:互联网 发布:网络学历国家认可吗 编辑:程序博客网 时间:2024/06/11 22:23

特点概要

Square的retrofit作为目前android比较火的网络框架,具有以下特点:

1、rest api 风格
2、网络核心使用优秀开源框架okttp,其本身致力于组装request和便捷转换response。
3、代码简洁,拓展性高,开发包只有90k左右
4、支持RxJava、Guava、Java8等适配器。

简单使用

案例是一个简单的登陆请求案例。使用name和pwd参数登陆接口,返回获取response并直接转换成User对象,User有两个成员变量name,age。

使用步骤分解为:
1、创建retrofit

private void initRetrofit(){         retrofit = new Retrofit.Builder()                .baseUrl("http://192.168.56.1:12306/")                .addConverterFactory(GsonConverterFactory.create())                .build();}

2、定义接口

public interface ApiServicce {    @FormUrlEncoded    @POST("/user/login/")    Call<User> login(@Field("name")String name, @Field("pwd")String pwd);}

3、创建Call代理对象

 ApiServicce apiService = retrofit.create(ApiServicce.class); Call<User> userCall = apiService.login("name","retrofit");

4、发起请求并获取回调内容

    @Override    public void onResponse(Call<User> call, Response<User> response) {              User user = response.body();          }            @Override            public void onFailure(Call<User> call, Throwable t) {                System.err.println(call.toString());            }   });

以上四个步骤就完成了一个完成的数据请求和回复的解析。高度解耦的特点只能用简洁优雅来形容。那么他怎么做到的呢我们稍后分析。这里涉及到一个的接口是使用mockserver来模拟完成的,有关于mockserver的工作可以从github mockserver了解。这里我使用的是简易的moco,只需要是简单使用其jar包和定义一个配置便可以轻松的完成一次模拟过程。详情可以参考这里。

服务启动命令:
java -jar moco-runner-0.11.0-standalone.jar http -p 12306 -c foo.json

foo.json内容:

[  {    "request" :    {      "uri" :"/user/login/",      "method" :"post"    },   "response" :      {        "json" :        {            "name" : "jerry",            "age" :"24"        }               }  },  {    "request":    {        "uri" : "/"    },    "response" :    {        "text" : "hello"    }  }]

可以看出调用
http://192.168.56.1:12306/返回hello的文本内容,调用http://192.168.56.1:12306/user/login 返回上述的json串再经由retrofit转换成对应的java对象。ok,大体了解了使用方法,开始剖析他的工作原理。

原理剖析

retrofit 工作流程
可以看出其工作流程主要分为下面四步

  • 1、首先build request参数
  • 2、因为不能在主线程请求HTTP,所以你得有个Executer或者线程
  • 3、enqueue后,通过线程去run你的请求
  • 4、得到服务器数据后,callback回调给你的上层。
  • 下面对其源码进行分析:
    结合我们使用过程 retrofit build

    retrofit build

    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) {        callbackExecutor = platform.defaultCallbackExecutor();      }      // Make a defensive copy of the adapters and add the default Call adapter.      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));      // Make a defensive copy of the converters.      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,          callbackExecutor, validateEagerly);    }

    实例CallFactory,CallFactory决定调用的网络模块使用的是哪个,这里默认使用的是OkHttpClient。成员callbackExecutor为执行回调的任务或线程。成员adapterFactories存放CallAdapter的一个列表,并且add一个默认的AdapterFactory,AdapterFactory中get方法用来获取到指定的CallAdapter。先来看下默认的AdapterFactory是什么,位置ExecutorCallAdapterFactory类。

    CallAdapter

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

    return new ExecutorCallbackCall,那么看下这个ExecutorCallbackCall是什么

    static final class ExecutorCallbackCall<T> implements Call<T> {    final Executor callbackExecutor;    final Call<T> delegate;    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {      this.callbackExecutor = callbackExecutor;      this.delegate = delegate;    }    @Override public void enqueue(final Callback<T> callback) {      if (callback == null) throw new NullPointerException("callback == null");      delegate.enqueue(new Callback<T>() {        @Override public void onResponse(Call<T> call, final Response<T> response) {          callbackExecutor.execute(new Runnable() {            @Override public void run() {              if (delegate.isCanceled()) {                // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.                callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));              } else {                callback.onResponse(ExecutorCallbackCall.this, response);              }            }          });        }        @Override public void onFailure(Call<T> call, final Throwable t) {          callbackExecutor.execute(new Runnable() {            @Override public void run() {              callback.onFailure(ExecutorCallbackCall.this, t);            }          });        }      });    }    @Override public boolean isExecuted() {      return delegate.isExecuted();    }    @Override public Response<T> execute() throws IOException {      return delegate.execute();    }    @Override public void cancel() {      delegate.cancel();    }    @Override public boolean isCanceled() {      return delegate.isCanceled();    }    @SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.    @Override public Call<T> clone() {      return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());    }    @Override public Request request() {      return delegate.request();    }  }

    ok,很简单。只是一个Call的代理类,不了解Call对象的可以去研究下okhttp。delegate.enqueue回复之后使用callbackExecutor将回复处理放回到一个子线程交由callback处理。做好这些准备工作之后。需要看下他是如果做到create代理对象的解耦和连接整个的工作流程。

    retrofit create

    retrofit.create(申明的接口class)

    public <T> T create(final Class<T> service) {    Utils.validateServiceInterface(service);    if (validateEagerly) {      eagerlyValidateMethods(service);    }    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, 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);            }            ServiceMethod serviceMethod = loadServiceMethod(method);            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);            return serviceMethod.callAdapter.adapt(okHttpCall);          }        });  }

    可以看出这里使用了一个动态代理来代理service类,观察其InvocationHandler代理改变的部分,其Object的方法都自动被原样的执行,当调用service里面的请求方法的时候会被Proxy拦截,loadServiceMethod方法讲原方法包装成ServiceMethod,ServiceMethod类主要工作是解析注解、传参,将他们分装成request,然后再根据具体的返回值,将之前配置的工场Factory生成具体的CallAdapter和ResponseConvert。 OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args)。显式的实例了一个OkhttpCall对象,OkHttpCall封装了Call(okhttp中的对象),说明retrofit是使用了okttp最为网络的核心模块。最后一步serviceMethod.callAdapter.adapt(okHttpCall),callAdater是用来做什么的呢,其本质是将call转成一个T型的策略。下面先对CallAdapter如何工作的进行剖析,并且如何整合Rxjava来使用的。

    结合Rxjava

    如果我们想使用Rxjava 那么接口方法定义得是这样的

        @FormUrlEncoded    @POST    Observable<User> rxLogin(@Field("name")String name, @Field("pwd")String pwd);

    那么如何才能转换成我们想要的Observable类型呢,前面我们说过CallAdapter旨在转换Call成为我们想要的T类型。那么需要在CallAdapter上做文章了。重点看下RxJavaCallAdapterFactory类

    public final class RxJavaCallAdapterFactory implements CallAdapter.Factory

    CallAdapter.Factory是Retrofit这个库中的接口,用来给我们自定义去解析我们自己想要的类型用的。

    get方法获取CallAdapter的方法

    @Overridepublic CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {    Class<?> rawType = Utils.getRawType(returnType);    boolean isSingle = "rx.Single".equals(rawType.getCanonicalName());    if (rawType != Observable.class && !isSingle) {      return null;    }    if (!(returnType instanceof ParameterizedType)) {      String name = isSingle ? "Single" : "Observable";      throw new IllegalStateException(name + " return type must be parameterized"          + " as " + name + "<Foo> or " + name + "<? extends Foo>");    }    CallAdapter<Observable<?>> callAdapter = getCallAdapter(returnType);    if (isSingle) {      // Add Single-converter wrapper from a separate class. This defers classloading such that      // regular Observable operation can be leveraged without relying on this unstable RxJava API.      return SingleHelper.makeSingle(callAdapter);    }    return callAdapter;}

    如果不是Observable的类型,则不去处理.Observable类型则调用callAdapter()方法获取对应的CallAdapter。callAdapter()方法中return SimpleCallAdapter的实例,那么观察SimpleCallAdapter的实现

    static final class SimpleCallAdapter implements CallAdapter<Observable<?>> {    private final Type responseType;    private final Scheduler scheduler;    SimpleCallAdapter(Type responseType, Scheduler scheduler) {      this.responseType = responseType;      this.scheduler = scheduler;    }    @Override public Type responseType() {      return responseType;    }    @Override public <R> Observable<R> adapt(Call<R> call) {      Observable<R> observable = Observable.create(new CallOnSubscribe<>(call)) //          .lift(OperatorMapResponseToBodyOrError.<R>instance());      if (scheduler != null) {        return observable.subscribeOn(scheduler);      }      return observable;    }  }

    好了,最终我们看到了adapter返回类型就是Observeble了。再回顾下retrofit create的过程中我们代理proxy return的结果是serviceMethod.callAdapter.apater(call)那么我们取得的是不是就一个Observerble对象了!!!那么create拿到的代理对象就是一个observable对象。就可以轻松的使用Rxjava了!!!如果不了解rxjava的可以了解下github rxjava

    Request and Response

    retrofit的重点是是组装request和回复response类型的转换。serviceMethod类是用来根据注解组装请求参数的。serviceMethod的build方法

    public ServiceMethod build() {      callAdapter = createCallAdapter();      responseType = callAdapter.responseType();      if (responseType == Response.class || responseType == okhttp3.Response.class) {        throw methodError("'"            + Utils.getRawType(responseType).getName()            + "' is not a valid response body type. Did you mean ResponseBody?");      }      responseConverter = createResponseConverter();      for (Annotation annotation : methodAnnotations) {        parseMethodAnnotation(annotation);      }      if (httpMethod == null) {        throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");      }      if (!hasBody) {        if (isMultipart) {          throw methodError(              "Multipart can only be specified on HTTP methods with request body (e.g., @POST).");        }        if (isFormEncoded) {          throw methodError("FormUrlEncoded can only be specified on HTTP methods with "              + "request body (e.g., @POST).");        }      }      int parameterCount = parameterAnnotationsArray.length;      parameterHandlers = new ParameterHandler<?>[parameterCount];      for (int p = 0; p < parameterCount; p++) {        Type parameterType = parameterTypes[p];        if (Utils.hasUnresolvableType(parameterType)) {          throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",              parameterType);        }        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];        if (parameterAnnotations == null) {          throw parameterError(p, "No Retrofit annotation found.");        }        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);      }      if (relativeUrl == null && !gotUrl) {        throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);      }      if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {        throw methodError("Non-body HTTP method cannot contain @Body.");      }      if (isFormEncoded && !gotField) {        throw methodError("Form-encoded method must contain at least one @Field.");      }      if (isMultipart && !gotPart) {        throw methodError("Multipart method must contain at least one @Part.");      }      return new ServiceMethod<>(this);    }

    createCallAdapter创建对应的callAdapter,即从CallAdapterFactory中取出需要的适配器,responseConverter创建对应的回复处理类,从List

    @Override public void enqueue(final Callback<T> callback) {    if (callback == null) throw new NullPointerException("callback == null");    okhttp3.Call call;    Throwable failure;    synchronized (this) {      if (executed) throw new IllegalStateException("Already executed.");      executed = true;      call = rawCall;      failure = creationFailure;      if (call == null && failure == null) {        try {          call = rawCall = createRawCall();        } catch (Throwable t) {          failure = creationFailure = t;        }      }    }    if (failure != null) {      callback.onFailure(this, failure);      return;    }    if (canceled) {      call.cancel();    }    call.enqueue(new okhttp3.Callback() {      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)          throws IOException {        Response<T> response;        try {          response = parseResponse(rawResponse);        } catch (Throwable e) {          callFailure(e);          return;        }        callSuccess(response);      }      @Override public void onFailure(okhttp3.Call call, IOException e) {        try {          callback.onFailure(OkHttpCall.this, e);        } catch (Throwable t) {          t.printStackTrace();        }      }      private void callFailure(Throwable e) {        try {          callback.onFailure(OkHttpCall.this, e);        } catch (Throwable t) {          t.printStackTrace();        }      }      private void callSuccess(Response<T> response) {        try {          callback.onResponse(OkHttpCall.this, response);        } catch (Throwable t) {          t.printStackTrace();        }      }    });  }

    使用okttp的call对象拿到回复之后调用parseResponse获得到指定的response对象。最终是调用serviceMethod中的toResponse进行转换成对应的T类型。

     /** Builds a method return value from an HTTP response body. */  T toResponse(ResponseBody body) throws IOException {    return responseConverter.convert(body);  }

    所以这里就是使用了我们指定的responseConverter进行转换。如GsonConverterFactory。转换的方式根据不同Converter来定,不做详述。由此可见,通过ServiceMethod的协调完成了request的组装和response回复的转换。

    0 0
    原创粉丝点击