浅析okhttp和Retrofit(二)

上篇文章我们主要介绍了okhttp的使用及实现原理,这篇文章我们来解析下Retrofit

前言

Retrofit其实我们可以理解为OkHttp的加强版,它也是一个网络加载框架,和OkHttp同样出自Square公司。Retrofit内部依赖于OkHttp,但是功能上做了更多的扩展,比如返回结果的转换功能,可以直接对返回数据进行处理。准确来说,网络请求的工作本质上是OkHttp完成,而 Retrofit 仅负责网络请求接口的封装。

Retrofit特点是包含了特别多注解,方便简化你的代码量
这里我们借用三张图来简单说明下上面用到的注解:

第一类:网络请求方法
第二类:标记
第三类:网络请求参数

Retrofit基本用法

配置
在build.grale添加如下依赖:

  // Okhttp库
  compile 'com.squareup.okhttp3:okhttp:3.10.0'
   // Retrofit库
   compile 'com.squareup.retrofit2:retrofit:2.4.0

创建用于描述网络请求的接口

@POST("passport/api/auth/login")
Observable<TokenInfoBean> mobileLogin(@Body RequestBody body);

@GET("platform/api/user/get_user_info/{key}")
Observable<AccountInfoBean> getUserInfo(@Path("key") int key);

创建Retrofit对象

 @Override
public <T> T obtainRetrofitService(Class<T> service) {
    //添加拦截器
    HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
    loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
    OkHttpClient okHttpClient = new OkHttpClient.Builder()
            .addInterceptor(loggingInterceptor)
            .addInterceptor(new ParamInterceptor(mApplication))
            .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
            .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
            .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
            .build();
    T t  = new Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create())  ////添加一个转换器,将gson数据转换为bean类
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())  ////添加一个适配器,与RxJava配合使用
            .client(okHttpClient)
            .baseUrl("xxxxxxx")
            .build()
            .create(service);
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }, new  ProxyHandler(t,this));
}

此处特意说明一下Retrofit的网络请求的完整Url = 创建Retrofit实例时通过.baseUrl()设置的url
+网络请求接口的注解设置的

完成请求进行调用

 @Override
public void login(String json, OnDataCallback<TokenInfoBean> dataCallback) {
    apiHelper.obtainRetrofitService(ILoginApiService.class)
            .mobileLogin(RequestUtils.getRequestBody(json))
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .compose(dataCallback.getView().bindLifeycle())
            .subscribe(new HandleObserver<TokenInfoBean>(dataCallback));
}

@Override
public void readAccountInfo(int roleType, OnDataCallback<AccountInfoBean> dataCallback) {
    apiHelper.obtainRetrofitService(ILoginApiService.class)
            .getUserInfo(roleType)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .compose(dataCallback.getView().<AccountInfoBean>bindLifeycle())
            .subscribe(new HandleObserver<AccountInfoBean>(dataCallback));
}

这就是我们完成一次请求的流程,下面我们来分析下Retrofit是怎样实现这些功能的。

首先创建Retrofit实例
new Retrofit.Builder()
             .baseUrl("xxxxxxx")
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .client(okHttpClient)
            .build()

Retrofit实例是使用建造者模式通过Builder类进行创建的,我们来看看Retrofit类(下面只是部分代码)

  public final class Retrofit {
    private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
    // 网络请求配置对象(对网络请求接口中方法注解进行解析后得到的对象)
    // 作用:存储网络请求相关的配置,如网络请求的方法、数据转换器、网络请求适配器、网络请求工厂、基地址等

    private final HttpUrl baseUrl;
    // 网络请求的url地址

    private final okhttp3.Call.Factory callFactory;
    // 网络请求器的工厂
    // 作用:生产网络请求器(Call)
    // Retrofit是默认使用okhttp

    private final List<CallAdapter.Factory> adapterFactories;
    // 网络请求适配器工厂的集合
    // 作用:放置网络请求适配器工厂
    // 网络请求适配器工厂作用:生产网络请求适配器(CallAdapter)
    // 下面会详细说明


    private final List<Converter.Factory> converterFactories;
    // 数据转换器工厂的集合
    // 作用:放置数据转换器工厂
    // 数据转换器工厂作用:生产数据转换器(converter)

    private final Executor callbackExecutor;
    // 回调方法执行器

    private final boolean validateEagerly;
     // 标志位
     // 作用:是否提前对业务接口中的注解进行验证转换的标志位


    Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
             List<Converter.Factory> converterFactories, List<CallAdapter.Factory> callAdapterFactories,
             @Nullable Executor callbackExecutor, boolean validateEagerly) {
        this.callFactory = callFactory;
        this.baseUrl = baseUrl;
        this.converterFactories = unmodifiableList(converterFactories);
        this.adapterFactories = unmodifiableList(adapterFactories);
        // unmodifiableList(list)近似于UnmodifiableList<E>(list)
        // 作用:创建的新对象能够对list数据进行访问,但不可通过该对象对list集合中的元素进行修改
        this.callbackExecutor = callbackExecutor;
        this.validateEagerly = validateEagerly;

    }
}

我们可以看到构建一个Retrofit需要:

serviceMethod:包含所有网络请求信息的对象
baseUrl:网络请求的url地址
callFactory:网络请求工厂
adapterFactories:网络请求适配器工厂的集合
converterFactories:数据转换器工厂的集合
callbackExecutor:回调方法执行器

所谓xxxFactory、“xxx工厂”其实是设计模式中工厂模式的体现:将“类实例化的操作”与“使用对象的操作”分开,使得使用者不用知道具体参数就可以实例化出所需要的“产品”类。

提一下callFactory,她是网络请求工厂,我们可以看看他

 interface Factory {
      Call newCall(Request request);
 }

我们可以看到callFactory主要是生产网络请求执行器Call,Call在Retrofit里默认是OkHttp,在这里我们重新设置了下client,主要是为了添加一些拦截器和设置一些timeout时间

像上面的参数我们都可以通过Builder来进行构建,这里我们着重介绍下converterFactories(数据转换器工厂的集合),顾名思义这个肯定是我们用来处理数据的,Retrofit默认使用Gson进行解析
若使用其他解析方式(如Json、XML或Protocobuf),也可通过自定义数据解析器来实现(必须继承 Converter.Factory),在这里我们可以处理请求参数和返回响应数据,请求参数我们是通过Okhttp里面的拦截器进行处理的,上篇文章已经介绍了,这里我们就不做处理,我们主要是来讲讲返回数据的处理,因为很多时候我们会遇到一个这样的场景,token过期问题,我们可以在每个请求返回处处理,但是太过繁琐和冗余,Retrofit就给我们提供了一个地方统一处理我们的服务器返回的数据:

final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {

private final TypeAdapter<T> adapter;

GsonResponseBodyConverter(TypeAdapter<T> adapter) {
    this.adapter = adapter;
}

@Override
public T convert(ResponseBody value) throws IOException {
    try {
        String json = value.string();
        Log.e("","======ResponseBody==data==="+json);
        BaseResponse response = JSON.parseObject(json,BaseResponse.class);
        if (response.getCode() == ErrorCode.CODE_TOKEN_TIMEOUT) {
            throw new TokenNotExistException();
        } else if (response.getCode() == ErrorCode.CODE_TOKEN_STRING_ERROR) {
            throw new TokenInvalidException();
        } else if (response.getCode() == 200) {
            return adapter.fromJson(response.getData());
        } else {
            // 特定 API 的错误,在相应的 Subscriber 的 onError 的方法中进行处理
            throw new ApiException(response.getCode(),response.getMessage());
        }
    } finally {
        value.close();
    }
}

我们可以看到当我们检测到服务器返回数据标明使用的token已经过期或者不存在,我们就可以相应的异常进行处理,其他的异常统一处理为业务异常,正常的我们就返回相应的数据就行了。

我们再来看看构建Retrofit实例中的build()方法:

 public Retrofit build() {

      <--  配置网络请求执行器(callFactory)-->
            okhttp3.Call.Factory callFactory = this.callFactory;
    // 如果没指定,则默认使用okhttp
    // 所以Retrofit默认使用okhttp进行网络请求
    if (callFactory == null) {
        callFactory = new OkHttpClient();
    }
    <--  配置回调方法执行器(callbackExecutor)-->
            Executor callbackExecutor = this.callbackExecutor;
    // 如果没指定,则默认使用Platform检测环境时的默认callbackExecutor
    // 即Android默认的callbackExecutor
    if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
    }

     <--  配置网络请求适配器工厂(CallAdapterFactory)-->
            List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
    // 向该集合中添加了步骤2中创建的CallAdapter.Factory请求适配器(添加在集合器末尾)
    adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
    // 请求适配器工厂集合存储顺序:自定义1适配器工厂、自定义2适配器工厂...默认适配器工厂(ExecutorCallAdapterFactory)

     <--  配置数据转换器工厂:converterFactory -->
            // 在步骤2中已经添加了内置的数据转换器BuiltInConverters()(添加到集合器的首位)
            // 在步骤4中又插入了一个Gson的转换器 - GsonConverterFactory(添加到集合器的首二位)
            List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
      // 数据转换器工厂集合存储的是:默认数据转换器工厂( BuiltInConverters)、自定义1数据转换器工厂(GsonConverterFactory)、自定义2数据转换器工厂....

      // 注:
       //1. 获取合适的网络请求适配器和数据转换器都是从adapterFactories和converterFactories集合的首位-末位开始遍历
     // 因此集合中的工厂位置越靠前就拥有越高的使用权限

    // 最终返回一个Retrofit的对象,并传入上述已经配置好的成员变量
    return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
            callbackExecutor, validateEagerly);
}

在最后一步中,通过前面步骤设置的变量,将Retrofit类的所有成员变量都配置完毕。如果前面没有配置的,都是用Retrofit默认的。自此一个Retrofit就构建完了,由于使用了建造者模式,所以开发者并不需要关心配置细节就可以创建好Retrofit实例。在创建Retrofit对象时,你可以通过更多更灵活的方式去处理你的需求,如使用不同的Converter、使用不同的CallAdapter,这也就提供了你使用RxJava来调用Retrofit的可能。

创建Call (网络请求接口的创建)##
 T t  = new Retrofit.Builder()
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .client(okHttpClient)
        .baseUrl("xxxxxxx")
        .build()
        .create(service);
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }, new  ProxyHandler(t,this));

我们构建完Retrofit后就会调用create(service)方法,进行创建接口实例,我们先看看create方法源码:

@SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
 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, @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);
        }
        if (platform.isDefaultMethod(method)) {
          return platform.invokeDefaultMethod(method, service, proxy, args);
        }
        ServiceMethod<Object, Object> serviceMethod =
            (ServiceMethod<Object, Object>) loadServiceMethod(method);
        OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
        return serviceMethod.adapt(okHttpCall);
      }
    });
   }

这里使用了动态代理,在这里和以往的动态代理和静态代理使用的场景是类似的,都想在delegate调用方法前后做一些操作。简而言之,动态代理就是拦截调用的那个方法,在方法前后来做一些操作。Retrofit里的动态代理比较巧妙。实际上它根本就没有delegate。因为这个方法没有真正的实现。使用动态代理,只是单纯的为了拿到这个method上所有的注解。所有的工作都是由proxy做了。比起我们总说代理就是打log要高明多了。

我们主要看Proxy.newProxyInstance方法,它接收三个参数,第一个是一个类加载器,其实哪个类的加载器都无所谓,这里为了方便就选择了我们所定义的接口的类加载器,第二个参数是我们定义的接口的class对象,第三个则是一个InvocationHandler匿名内部类。
那大家应该会有疑问了,这个newProxyInstance到底有什么用呢?其实他就是通过动态代理生成了网络请求接口的代理类,代理类生成之后,接下来我们就可以使用apiHelper.obtainRetrofitService(ILoginApiService.class).login(xxx),这样的语句去调用login方法,当我们调用这个方法的时候就会被动态代理拦截,直接进入InvocationHandler的invoke方法。下面就来讲讲它。

invoke方法

它接收三个参数,第一个是动态代理,第二个是我们要调用的方法,这里就是指login方法,第三个是一个参数数组,同样的这里就是指我们要传的参数,收到方法名和参数之后,紧接着会调用loadServiceMethod方法来生产过一个ServiceMethod对象,这里的一个ServiceMethod对象就对应我们在网络接口里定义的一个方法,相当于做了一层封装。接下来重点来看loadServiceMethod方法:

ServiceMethod<?, ?> loadServiceMethod(Method method) {
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;

synchronized (serviceMethodCache) {
  result = serviceMethodCache.get(method);
  if (result == null) {
    result = new ServiceMethod.Builder<>(this, method).build();
    serviceMethodCache.put(method, result);
  }
}
return result;
}

它调用了ServiceMethod类,而ServiceMethod也使用了Builder模式,直接先看Builder方法。

 Builder(Retrofit retrofit, Method method) {
  this.retrofit = retrofit;
  //获取接口中的方法名
  this.method = method;

  //获取方法里的注解
  this.methodAnnotations = method.getAnnotations();

  //获取方法里的参数类型 
  this.parameterTypes = method.getGenericParameterTypes();

  //获取接口方法里的注解内容 
  this.parameterAnnotationsArray = method.getParameterAnnotations();
}

从上面可以看出,因为Retrofit使用了大量的注解,我们在这里就可以通过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);
}

我们可以理一下,这里主要做了以下工作:

1、首先对注解的合法性进行检验,例如,HTTP的请求方法是GET还是POST,如果不是就会抛出异常;
2、根据方法的返回值类型和方法注解从Retrofit对象的的callAdapter列表和Converter列表中分别获取到该方法对应的callAdapter和Converter;
3、将传递进来的参数与注解封装在parameterHandlers中,为后面的网络请求做准备。

进行到这里我们只有差发起网络请求了,回到crete方法里面的invoke方法最后两行:

 OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
    return serviceMethod.adapt(okHttpCall);

这里将serviceMethod与我们实际传入的参数传递给了OkHttpCall,接下来就来瞧瞧这个类做了些什么:

final class OkHttpCall<T> implements Call<T> {
private final ServiceMethod<T, ?> serviceMethod;   // 含有所有网络请求参数信息的对象
private final @Nullable Object[] args;  // 网络请求接口的参数 

private volatile boolean canceled;

@GuardedBy("this")
private @Nullable okhttp3.Call rawCall;  //实际进行网络访问的类  
@GuardedBy("this") // Either a RuntimeException, non-fatal Error, or IOException.
private @Nullable Throwable creationFailure;  //几个状态标志位  
@GuardedBy("this")
private boolean executed;

OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
  // 传入了配置好的ServiceMethod对象和输入的请求参数
  this.serviceMethod = serviceMethod;
  this.args = args;
}
  。。。。。。
}

配置好这些,接着调用serviceMethod.adapt(okHttpCall),这里将创建的OkHttpCall对象传给上面创建的serviceMethod对象中对应的网络请求适配器工厂的adapt()

T adapt(Call<R> call) {
    return callAdapter.adapt(call);
}

点击进方法我们可以看到 callAdapter.adapt(call),构建Retrofit我们build传入的是.addCallAdapterFactory(RxJava2CallAdapterFactory.create()),看下里面实现的adapt():

 @Override public Object adapt(Call<R> call) {
Observable<Response<R>> responseObservable = isAsync
    ? new CallEnqueueObservable<>(call)
    : new CallExecuteObservable<>(call);

Observable<?> observable;
if (isResult) {
  observable = new ResultObservable<>(responseObservable);
} else if (isBody) {
  observable = new BodyObservable<>(responseObservable);
} else {
  observable = responseObservable;
}

if (scheduler != null) {
  observable = observable.subscribeOn(scheduler);
}

if (isFlowable) {
  return observable.toFlowable(BackpressureStrategy.LATEST);
}
if (isSingle) {
  return observable.singleOrError();
}
if (isMaybe) {
  return observable.singleElement();
}
if (isCompletable) {
  return observable.ignoreElements();
}
return observable;
}

首先在adapt方法中会先判断是同步请求还是异步请求,这里我们以同步请求为例,直接看CallExecuteObservable:

@Override protected void subscribeActual(Observer<? super Response<T>> observer) {
// Since Call is a one-shot type, clone it for each new observer.
Call<T> call = originalCall.clone();
CallDisposable disposable = new CallDisposable(call);
observer.onSubscribe(disposable);

boolean terminated = false;
try {
  Response<T> response = call.execute();   
  if (!disposable.isDisposed()) {
    observer.onNext(response);
  }
  if (!disposable.isDisposed()) {
    terminated = true;
    observer.onComplete();
  }
} catch (Throwable t) {
  Exceptions.throwIfFatal(t);
  if (terminated) {
    RxJavaPlugins.onError(t);
  } else if (!disposable.isDisposed()) {
    try {
      observer.onError(t);
    } catch (Throwable inner) {
      Exceptions.throwIfFatal(inner);
      RxJavaPlugins.onError(new CompositeException(t, inner));
    }
  }
}
}

万里长征终于走到了最后一步,在subscribeActual方法中去调用了OKHttpCall的execute方法开始进行网络请求,具体OKHttpCall是怎么发起网络请求的可以看下我上一篇文章。网络请求完毕之后,会通过RxJava的操作符对返回来的数据进行转换,并进行线程的切换,至此,Retrofit的一次使用也就结束了。

在最后在解释下在创建网络请求接口的时候我又使用了代理:

return (T) Proxy.newProxyInstance(service.getClassLoader(), 
   new Class<?>[] { service }, new  ProxyHandler(t,this));

我们可以看看我的ProxyHandler做了什么事:

public class ProxyHandler implements InvocationHandler {

private final static String TAG = "Token_Proxy";

private final static String TOKEN = "token";

private final static int REFRESH_TOKEN_VALID_TIME = 30;
private static long tokenChangedTime = 0;
private Throwable mRefreshTokenError = null;

private Object mProxyObject;

RHttpHelper helper;

public ProxyHandler(Object proxyObject,RHttpHelper helper) {
    mProxyObject = proxyObject;
    this.helper = helper;
}

@Override
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
    return Observable.just("sxt").flatMap(new Function<Object, ObservableSource<?>>() {

        @Override
        public ObservableSource<?> apply(Object o) throws Exception {
            try {
                try {
                    return (Observable<?>) method.invoke(mProxyObject, args);
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            return null;
        }
    }).retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() {
        @Override
        public ObservableSource<?> apply(Observable<Throwable> throwableObservable) throws Exception {
            return throwableObservable.flatMap(new Function<Throwable, ObservableSource<?>>() {
                @Override
                public ObservableSource<?> apply(Throwable throwable) throws Exception {
                    if (throwable instanceof TokenInvalidException) {
                                                        //刷新token
                                                       return refreshTokenWhenTokenInvalid();
                                                   } else if (throwable instanceof TokenNotExistException) {
                                                       // Token 不存在,执行退出登录的操作。(为了防止多个请求,都出现 Token 不存在的问题,
                                                       // 这里需要取消当前所有的网络请求)
                                                       return Observable.error(throwable);
                                                   }
                                                   return Observable.error(throwable);
                }
            });
        }
    });
}

前面提到了在GsonResponseBodyConverter我们捕获了异常信息(token过期),并且抛出了异常,我们就在这里捕获了该异常,比如token过期我们就可以进行刷新token处理,如果是token不存在就执行退出登录操作。里面涉及到的Rxjava的会在下一篇文章解析。

总结

从上面的分析,我们队Retrofit应该有了一个大概的了解,其实retrofit就是一个负责调度的controller。你给它一个方法调用,它就在内部开始运转。通过动态代理,用一个ServiceMethod来解析它。解析后完成后配置一个request请求。但它自己搞不定这事啊,所以需要给它一个转接头callAdapter,通过转接头来使用okhttp。使用okhttp发起请求后,获取响应数据response,但是它又不认识,所以又请来GsonConverterFactory来帮忙,转换完毕之后才给出一个我们最终要的那个对象。
与其说它是一个网络请求框架不如说他做了一层封装,通过大量的设计模式 ,使得我们能够更方便的间接使用RxJava与OkHttp,整个框架的耦合度大大降低,调用者也使用得更加简洁。
下一篇文章我们在继续介绍Rxjava。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,402评论 6 499
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,377评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,483评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,165评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,176评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,146评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,032评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,896评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,311评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,536评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,696评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,413评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,008评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,815评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,698评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,592评论 2 353

推荐阅读更多精彩内容