标签(空格分隔): Retrofit RxJavajava
Android 6.0(SDK 23)推出后,Apache的HttpClient被弃用。以前一些经常使用的框架如xUtils,android-async-http都须要依赖HttpClient,如今用起来都不方便了。幸亏有Retrofit补上这个漏,并且还被得更好。 Retrofit是Square公司出口的一个网络请求框架,本质上是对OkHttp的包装,很是适合Android平台使用。目前最新版本是2.0 beta2,因此下面所说的Retrofit都是指Retrofit 2.0。react
在看源码以前,咱们先熟悉一下Retrofit的使用方式。下面介绍两种使用Retrofit的方式,分别是Call<T>方式和RxJava方式。都是基于Gradle。在项目中建立项目以后,android
在项目的build.gradle文件中添加Retrofit的依赖,git
compile 'com.squareup.retrofit:retrofit:2.0.0-beta2' compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'
建立实体类和一个接口,以下github
public class GithubUser { public String login; public String avatar_url; public String company; } public interface GithubApi { @GET("users/{user}") Call<GithubUser> getUserInfoByName(@Path("user") String name); }
初创化Retrofit对象,以及实例化GithubApi编程
Retrofit mRetrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/") // 这里有一个坑,若是项目不是部署在域名根目录下,则必需要以“/”结尾,不然出错。在1.9以及以前,url是不能以“/”结尾的。 .addConverterFactory(GsonConverterFactory.create(gson)) .client(mClient) .build(); GithubApi api = mRetrofit.create(GithubApi.class);
而后就能够请求数据了api
api.getUserInfoByName("atanl").enqueue(new Callback<GithubUser>() { @Override public void onResponse(Response<GithubUser> response, Retrofit retrofit) { Toast.makeText(getApplicationContext(), response.body().login, Toast.LENGTH_SHORT).show(); } @Override public void onFailure(Throwable t) { t.printStackTrace(); } });
上面代码涉及了两个步骤,获取到一个Call<GithubUser>实例,而后调用它的enqueue方法。其实在前一个步骤http请求是尚未发送的,只有调用的enqueue方法以后才开始请求。这和java基础多线程编程中的Call或者Future实际上是一个概念。关于Call<T>下面会有更多说明。缓存
和RxJava配合使用时,本质是对Call<T>这种方式的一个包装,就是把Call<T>实例转变成Observable<T>对象。等下作更多的说明,先看一下样例代码。ps,若是不知道RxJava是什么鬼的童鞋,能够参考给 Android 开发者的 RxJava 详解。网络
在上面的build.gradle的基础上再添加下面依赖,多线程
compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta2' compile 'io.reactivex:rxandroid:1.0.1'
在生成Retrofit实例的时候,添加一个RxJava的CallAdapterFactory。以下,
Retrofit mRetrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/") // 这里有一个坑,若是项目不是部署在域名根目录下,则必需要以“/”结尾,不然出错。在1.9以及以前,url是不能以“/”结尾的。 .addConverterFactory(GsonConverterFactory.create(gson)) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .client(mClient) .build();
向GithubApi接口添加一个方法。以下,
public interface GithubApi { @GET("users/{user}") Call<GithubUser> getUserInfoByName(@Path("user") String name); GET("users/{user}") Observable<GithubUser> getUserInfoObservable(@Path("user") String name); }
接下下来就是使用这个接口获取数据了,
api.getUserInfoObservable("atanl") .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(user -> { Toast.make(getApplicationContext(), user.login + "", Toast.LENGHT_SHORT).show(); });
上面代码中经过getUserInfoObservable获取获得的Observable<GithubUser>其实就是经过RxJavaCallAdapterFactory对Call<GithubUser>的一个转换。
看过上面的样例,不论是直接经过Call<T>方式仍是和RxJava配合使用,一个必经的步骤应是经过Retrofit的create方法来实例化一个接口实例(如GithubApi)。那么咱们就一直看一下create方法是怎么工做的。
public <T> T create(final Class<T> service) { ... 这里省略了若干行代码 return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() { // 留意这个代理实例 ... 这里省略了若干行代码 @Override public Object invoke(Object proxy, Method method, Object... args) throws Throwable { ... 这里省略了若干行代码 return loadMethodHandler(method).invoke(args); } }); }
上面代码说白了就是经过Java的动态代理机制,实例化一个实现了GithubApi的的代理客户端(即Proxy对象),而后调用GithubApi的方法时,操做会被代理到一个InvocationHandler中。如上面代码,对GithubApi中方法的访问其实都是代理到了最后一行代码
return loadMethodHandler(method).invoke(args);
很简单,意思就是去某个地方获取一个Handler出来,而后调用它来产生结果,而后做为接口方法的返回值。那么咱们继续跟进loadMethodHandler,看一下load出来的MethodHandler是长什么样子的。
MethodHandler<?> loadMethodHandler(Method method) { MethodHandler<?> handler; synchronized (methodHandlerCache) { handler = methodHandlerCache.get(method); if (handler == null) { handler = MethodHandler.create(this, method); // 这是是关键 methodHandlerCache.put(method, handler); } } return handler; }
这个方法中能够看出,Retrofit会先在缓存中找下是否是已经有如今的MethodHandler实例能够获取,若是有就直接拿出来用。不然,create一个。咱们先不用管它的缓存,只看create。因此继续,跟进create方法中,
static MethodHandler<?> create(Retrofit retrofit, Method method) { CallAdapter<Object> callAdapter = (CallAdapter<Object>) createCallAdapter(method, retrofit); Type responseType = callAdapter.responseType(); Converter<ResponseBody, Object> responseConverter = (Converter<ResponseBody, Object>) createResponseConverter(method, retrofit, responseType); RequestFactory requestFactory = RequestFactoryParser.parse(method, responseType, retrofit); return new MethodHandler<>(retrofit, requestFactory, callAdapter, responseConverter); }
这里有五行代码,每行都作了一件事。 第一,建立一个CallAdapter,这里是重点,等下详述。 第二,获取到接口(GithubApi)方法的返回值的泛型类型(两个方法都是GithubUser)。 第三,实例化一个数据结果的转换器,把Http请求所得的response转换成POJO。 第四,实例化一个请求工厂类,用于把带有@GET,@POST等注解的接口方法生成对的Http请求实例。 第五,返回咱们想要的MethodHandler对象。
当咱们拿到MethodHandler对象以后,就能够调用它的invoke方法来生成结果,而且接口方法的返回值。那么咱们再看MethodHandler的invoke方法,
Object invoke(Object... args) { return callAdapter.adapt(new OkHttpCall<>(retrofit, requestFactory, responseConverter, args)); // 记住这个OkHttpCall类 }
只是很简单的调用以前第一步获取到的CallAdapter实例的adapt方法。方法名很朴实,也很应景,意思就是适配,把一个Call<T>实例(即OkHttpCall<T>对象)适配成一个Call<T>实例(这种状况下,其实适配器就是直接返回Call<T>实例,没有作什么转换),或者一个Observale<T>实例(这种状况下,下面细说)。
这里涉及到两个关键点,一个是CallAdapater,一个是OkHttpCall<T>。后者咱们等下再说,先说CallAdapter。
CallAdapter只是一个接口,不能直接实例化。在Retrofit的体系中,全部的CallAdapter实例都是经过相应的CallAdapterFactory来产生的,如上面提到的RxCallAdapterFactory。
咱们先回到MethodHandler.create方法的第一行代码,即建立一个CallAdapter。跟进代码,看一下CallAdapterFactory是怎么生产出一个CallAdapter来。
private static CallAdapter<?> createCallAdapter(Method method, Retrofit retrofit) { Type returnType = method.getGenericReturnType(); ... // 这里省略了若干行代码。 Annotation[] annotations = method.getAnnotations(); try { return retrofit.callAdapter(returnType, annotations); } catch (RuntimeException e) { ... // 这里省略了若干行代码。 } } ////// public CallAdapter<?> callAdapter(Type returnType, Annotation[] annotations) { return nextCallAdapter(null, returnType, annotations); } ////// public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) { ... // 这里省略了若干行代码。 int start = adapterFactories.indexOf(skipPast) + 1; for (int i = start, count = adapterFactories.size(); i < count; i++) { CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this); if (adapter != null) { return adapter; } } ... // 这里省略了若干行代码。 }
从上面代码最后的循环中能够看出,CallAdapter实际上是经过遍历各个AdapterFactory来,而后根据返回接口方法的返回类型(如上面GithubApi的第二个方法的返回类型是Observable<T>)来决定由哪一个Factory来实例化CallAdapter。若是是返回类型是Observable<T>,那么就由RxCallAdapterFactory(在建立Retrofit时向其中注册)来代劳。
RxCallAdapterFactory实现了CallAdapter.Factory接口,因此咱们从get方法切入,
@Override public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) { ... // 这里省略若干行代码 CallAdapter<Observable<?>> callAdapter = getCallAdapter(returnType); ... // 这里省略若干行代码 return callAdapter; } private CallAdapter<Observable<?>> getCallAdapter(Type returnType) { Type observableType = Utils.getSingleParameterUpperBound((ParameterizedType) returnType); ... // 这里省略若干行代码 return new SimpleCallAdapter(observableType); }
上面代码中,咱们能够看到,RxCallAdapterFactory最后产生的CallAdapter其实就是一个SimpleCallAdapter实例。它实现了CallAdapter接口,因此咱们也来看一下他的adapt方法。
@Override public <R> Observable<R> adapt(Call<R> call) { return Observable.create(new CallOnSubscribe<>(call)) // .flatMap(new Func1<Response<R>, Observable<R>>() { @Override public Observable<R> call(Response<R> response) { if (response.isSuccess()) { return Observable.just(response.body()); } return Observable.error(new HttpException(response)); } }); }
上面代码涉及到了一个CallOnSubscribe类,它是Observable.OnSubscribe接口的一个实现。因此咱们来看下它的call方法。
@Override public void call(final Subscriber<? super Response<T>> subscriber) { ... // 这里省略若干行代码 try { Response<T> response = call.execute(); if (!subscriber.isUnsubscribed()) { subscriber.onNext(response); } } catch (Throwable t) { Exceptions.throwIfFatal(t); if (!subscriber.isUnsubscribed()) { subscriber.onError(t); } return; } if (!subscriber.isUnsubscribed()) { subscriber.onCompleted(); } }
上面代码意思很明显,调用Call<T>的execute方法访问网络数据,而且把结果转化为Observable的数据源。
好,到这里RxCallAdapterFactory的工做原理已经知道了,可能有童鞋会对Call<T>接口还有疑问。没有问题,下面就来看一个Call<T>的实现类——OkHttpCall<T>。
以前有说过Retrofit其实就是对OkHttp的一个包装。空穴来风,从这个OkHttpCall类就能够缘由。OkHttpCall类是Call接口一个实现,采起了委派模式,调用它的execute方法或者enqueue方法其实都是委派到com.squareup.okhttp.Call实例来实现,而后再把结果包装成POJO形式的Response。如execute方法的源码,
public Response<T> execute() throws IOException { synchronized (this) { ... // 这里省略若干行代码 com.squareup.okhttp.Call rawCall = createRawCall(); ... // 这里省略若干行代码 return parseResponse(rawCall.execute()); } private Response<T> parseResponse(com.squareup.okhttp.Response rawResponse) throws IOException { ResponseBody rawBody = rawResponse.body(); ... // 这里省略若干行代码 ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody); try { T body = responseConverter.convert(catchingBody); return Response.success(body, rawResponse); } catch (RuntimeException e) { ... // 这里省略若干行代码 } }
另外,Call<T>接口的enqueue方法其实和execute是差很少的,只不过是多线程方式运行。源码本身去看,要跟踪到OkHttp的Call<T>中,我懒得写了。
打完收工。