Retrofit源码学习笔记(2)-CallAdapter解析
2017-01-11 22:00
477 查看
Retrofit允许各种第三方库来对返回的HTTP call进行操作。因此这就要求Retrofit给出一套机制来使得API 请求和现有的第三库进行无缝的链接。这个机制就是CallAdapter,它可以将返回的 http call进行处理,从而适应不同的操作。
callAdapter使用了工厂模式,所以它的代码结构简练而又复杂。
这是CallAdapter的源码。其中factory是工厂,在我们自定义自己的CallAdapter时需要继承实现factory,其中的get方法用于生产我们想要的CallAdapter。getParameterUpperBound的作用是返回第index个参数的最上层的类。getRawType的作用是返回参数的原始的类型。比如List
这是一个简单的实现的结构。在adapt中我们可以对返回的call进行处理,将它封装成我们想要的格式,这里我想将它封装为ListenableFuture格式。
在Android平台上实现CallAdapter的类是ExecutorCallAdapterFactory。值得一提的这个类使用了装饰模式,从而使得在Call返回时调用我们想要的callback操作。核心代码如下所示(我只是展示了我认为对逻辑理解比较重要的代码,具体代码请看源码)
其中get方法会在ServiceMethod的bulid方法中被调用。用于生成默认的callAdapter。此外需要注意的是在retrofit的create的动态代理中的adapt函数调用的就是此处get中的adapt函数。
retrofit中的adapt
get中的adapt
因此在ExecutorCallbackCall便是在mainActivity中的 Call
所以可见,返回调用的执行的操作是在主线程上新建一个线程进行运行的。
ListenableFuture顾名思义就是可以监听的Future,它是对java原生Future的扩展增强。它是一个异步计算任务。
我们将module进行一下改变:
此处contributorsByAddConverterGetCall返回一个ListenableFuture
在adapt函数返回一个ListenableFuture对象,并赋予他一个Callable,在Callable中的call中执行网络请求事件。
然后我们在mainAcitivty中,我们获得这个ListenableFuture对象,并将赋予其监听事件。
我们知道Future表示一个异步计算任务,当任务完成时可以得到计算结果。如果我们希望一旦计算完成就拿到结果展示给用户或者做另外的计算,就必须使用另一个线程不断的查询计算状态。这样做,代码复杂,而且效率低下。使用ListenableFuture Guava帮我们检测Future是否完成了,如果完成就自动调用回调函数,这样可以减少并发程序的复杂度。
有一点需要指出的是,在Java8中的CompletableFuture收集了ListenableFuture in Guava 的所有特性,我们也可以使用它来得到我们想要的结果。
3.应用RxJava和Retrofit的结合。
Rxjava是一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库。简单的来说,它的作用就是异步,它的优势就是代码实现简单优雅。
对于RxJava不懂得同学,可以阅读https://github.com/ReactiveX/RxJava/wiki。
同样是上面那个例子。
Module
可以看出返回一个Observable
MainAcivity
相比于其他回调函数,Rxjava的链式结构确实能让人感到代码结构变得无比清晰,同时,Rxjava能够改变事件发生和事件消耗的线程,给开发者提供了更多的想象空间。
这是实例代码
https://github.com/zzg080643/Retrofit-test-example
callAdapter使用了工厂模式,所以它的代码结构简练而又复杂。
public interface CallAdapter<T> { Type responseType(); <R> T adapt(Call<R> call); abstract class Factory { public abstract retrofit2.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); } } }
这是CallAdapter的源码。其中factory是工厂,在我们自定义自己的CallAdapter时需要继承实现factory,其中的get方法用于生产我们想要的CallAdapter。getParameterUpperBound的作用是返回第index个参数的最上层的类。getRawType的作用是返回参数的原始的类型。比如List
public final class GuavaCallAdapterFactory extends CallAdapter.Factory { public static GuavaCallAdapterFactory create() { return new GuavaCallAdapterFactory(); } private GuavaCallAdapterFactory() { doSomethins() } @Override public CallAdapter<ListenableFuture<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) { return new CallAdapter<ListenableFuture<?>>() { @Override public Type responseType() { return responseType; } @Override public <R> ListenableFuture<R> adapt( final Call<R> call) { doSomething() } } }; } }
这是一个简单的实现的结构。在adapt中我们可以对返回的call进行处理,将它封装成我们想要的格式,这里我想将它封装为ListenableFuture格式。
几种CallAdapter应用的例子
1. Retrofit在Android平台默认的例子
先举个例子,MainActivity上的操作。Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/") .addConverterFactory(GsonConverterFactory.create()) .build(); uerService repo = retrofit.create(uerService.class); Call<List<Contributor>> call = repo.contributorsByAddConverterGetCall("square", "retrofit"); call.enqueue(new Callback<List<Contributor>>() { @Override public void onResponse(Call<List<Contributor>> call, Response<List<Contributor>> response) { List<Contributor> contributorList= response.body(); for(Contributor contributor : contributorList) { Log.d("login", contributor.getLogin()); Log.d("contributions", contributor.getContributions() + ""); } } @Override public void onFailure(Call<List<Contributor>> call, Throwable t) { } });
在Android平台上实现CallAdapter的类是ExecutorCallAdapterFactory。值得一提的这个类使用了装饰模式,从而使得在Call返回时调用我们想要的callback操作。核心代码如下所示(我只是展示了我认为对逻辑理解比较重要的代码,具体代码请看源码)
final class ExecutorCallAdapterFactory extends CallAdapter.Factory { final Executor callbackExecutor; ExecutorCallAdapterFactory(Executor callbackExecutor) { this.callbackExecutor = callbackExecutor; } @Override public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) { //doSomething(); @Override public <R> Call<R> adapt(Call<R> call) { return new ExecutorCallbackCall<>(callbackExecutor, call); } }; } 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) { delegate.enqueue(new Callback<T>() { @Override public void onResponse(Call<T> call, final Response<T> response) { callbackExecutor.execute(new Runnable() { @Override public void run() { 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); } }); } }); } } }
其中get方法会在ServiceMethod的bulid方法中被调用。用于生成默认的callAdapter。此外需要注意的是在retrofit的create的动态代理中的adapt函数调用的就是此处get中的adapt函数。
retrofit中的adapt
................ ................... return serviceMethod.callAdapter.adapt(okHttpCall);
get中的adapt
........... ........... @Override public <R> Call<R> adapt(Call<R> call) { return new ExecutorCallbackCall<>(callbackExecutor, call); }
因此在ExecutorCallbackCall便是在mainActivity中的 Call
static class MainThreadExecutor implements Executor { private final Handler handler = new Handler(Looper.getMainLooper()); @Override public void execute(Runnable r) { handler.post(r); } }
所以可见,返回调用的执行的操作是在主线程上新建一个线程进行运行的。
2.应用ListenableFuture的CallAdapter
将future与CallAdapter进行结合,其好处是可以将http 请求和对返回结果的操作隔离开来。我们可以应用Guava的ListenableFuture进行示例。ListenableFuture顾名思义就是可以监听的Future,它是对java原生Future的扩展增强。它是一个异步计算任务。
我们将module进行一下改变:
public interface userServiceGuva { @GET("repos/{owner}/{repo}/contributors") ListenableFuture<List<Contributor>> contributorsByAddConverterGetCall (@Path("owner") String owner, @Path("repo") String repo); }
此处contributorsByAddConverterGetCall返回一个ListenableFuture
public final class GuavaCallAdapterFactory extends CallAdapter.Factory { public static GuavaCallAdapterFactory create() { return new GuavaCallAdapterFactory(); } private GuavaCallAdapterFactory() { } @Override public CallAdapter<ListenableFuture<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) { if (getRawType(returnType) != ListenableFuture.class) { return null; } if (!(returnType instanceof ParameterizedType)) { throw new IllegalStateException("ListenableFuture return type must be parameterized" + " as ListenableFuture<Foo> or ListenableFuture<? extends Foo>"); } final Type responseType = getParameterUpperBound(0, (ParameterizedType) returnType); return new CallAdapter<ListenableFuture<?>>() { @Override public Type responseType() { return responseType; } @Override public <R> ListenableFuture<R> adapt( final Call<R> call) { ListeningExecutorService executorService = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool()); final ListenableFuture<R> listenableFuture = executorService.submit(new Callable<R>() { @Override public R call() throws Exception { return call.execute().body(); } }); return listenableFuture; } }; } }
在adapt函数返回一个ListenableFuture对象,并赋予他一个Callable,在Callable中的call中执行网络请求事件。
然后我们在mainAcitivty中,我们获得这个ListenableFuture对象,并将赋予其监听事件。
Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/") .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(GuavaCallAdapterFactory.create()) .build(); userServiceGuva reto = retrofit.create(userServiceGuva.class); final ListenableFuture<List<Contributor>> future = reto.contributorsByAddConverterGetCall("square", "retrofit"); Futures.addCallback(future, new FutureCallback<List<Contributor>>() { @Override public void onSuccess(List<Contributor> result) { for(Contributor contributor : result) { Log.d("Guva_login", contributor.getLogin()); Log.d("Guva_contributions", contributor.getContributions() + ""); } } @Override public void onFailure(Throwable t) { } });
我们知道Future表示一个异步计算任务,当任务完成时可以得到计算结果。如果我们希望一旦计算完成就拿到结果展示给用户或者做另外的计算,就必须使用另一个线程不断的查询计算状态。这样做,代码复杂,而且效率低下。使用ListenableFuture Guava帮我们检测Future是否完成了,如果完成就自动调用回调函数,这样可以减少并发程序的复杂度。
有一点需要指出的是,在Java8中的CompletableFuture收集了ListenableFuture in Guava 的所有特性,我们也可以使用它来得到我们想要的结果。
3.应用RxJava和Retrofit的结合。
Rxjava是一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库。简单的来说,它的作用就是异步,它的优势就是代码实现简单优雅。
对于RxJava不懂得同学,可以阅读https://github.com/ReactiveX/RxJava/wiki。
同样是上面那个例子。
Module
public interface uerServiceRx { @GET("repos/{owner}/{repo}/contributors") Observable<List<Contributor>> contributorsByAddConverterGetCall (@Path("owner") String owner, @Path("repo") String repo); }
可以看出返回一个Observable
public class RxCallAdapter<R> implements CallAdapter<R> { private final Type responseType; private final Scheduler scheduler; public RxCallAdapter(Type responseType, Scheduler scheduler) { this.responseType = responseType; this.scheduler = scheduler; } @Override public Type responseType() { return responseType; } @Override public <R1> R adapt(Call<R1> call) { Observable<?> observable = Observable.create(new CallOnSubscribe<>(call)); if(scheduler != null ){ observable = observable.subscribeOn(scheduler); } return (R)observable; } }
MainAcivity
Subscriber<List<Contributor>> delegate = new Subscriber<List<Contributor>>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(List<Contributor> contributors) { for(Contributor contributor : contributors) { Log.d("Guva_login", contributor.getLogin()); Log.d("Guva_contributions", contributor.getContributions() + ""); } } }; Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/") .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxCallAdapterFactory.create()) .build(); uerServiceRx reto = retrofit.create(uerServiceRx.class); reto.contributorsByAddConverterGetCall("square", "retrofit").subscribeOn(Schedulers.newThread()) .observeOn(Schedulers.io()).subscribe(new ForwardingSubscriber<List<Contributor>>(delegate)); }
相比于其他回调函数,Rxjava的链式结构确实能让人感到代码结构变得无比清晰,同时,Rxjava能够改变事件发生和事件消耗的线程,给开发者提供了更多的想象空间。
这是实例代码
https://github.com/zzg080643/Retrofit-test-example
相关文章推荐
- Jsoup学习笔记3:Jsoup 解析Html源码实例
- 第44讲:Scala中View Bounds代码实战及其在Spark中的应用源码解析学习笔记
- 第59讲:Scala中隐式转换初体验实战详解以及隐式转换在Spark中的应用源码解析学习笔记
- AngularJS学习笔记--002--Angular JS路由插件ui.router源码解析
- Scala中上下文界定内幕中的隐式参数与隐式参数的实战详解及其在Spark中的应用源码解析之Scala学习笔记-52
- Jsoup学习笔记4:Jsoup 解析Html源码实例
- Scala中Context Bounds代码实战及其在Spark中的应用源码解析之Scala学习笔记-36
- Scala中隐式转换初体验实战详解以及隐式转换在Spark中的应用源码解析之Scala学习笔记-49
- Scala类型约束代码实战及其在Spark中的应用源码解析之Scala学习笔记-39
- Scala并发编程实战初体验及其在Spark源码中的应用解析之Scala学习笔记-56
- 第67讲:Scala并发编程匿名Actor、消息传递、偏函数实战解析及其在Spark源码中的应用解析学习笔记
- 第50讲:Scala中Variance变化点及其在Spark中的应用源码解析学习笔记
- Scala中隐式参数实战详解以及隐式参数在Spark中的应用源码解析之Scala学习笔记-50
- 第45讲:Scala中Context Bounds代码实战及其在Spark中的应用源码解析学习笔记
- 第43讲:Scala中类型变量Bounds代码实战及其在Spark中的应用源码解析学习笔记
- 第49讲:Scala中Variance代码实战及其在Spark中的应用源码解析学习笔记
- Scala中类型变量Bounds代码实战及其在Spark中的应用源码解析之Scala学习笔记-34
- 第60讲:Scala中隐式参数实战详解以及隐式参数在Spark中的应用源码解析学习笔记
- Scala中隐式转换内幕操作规则揭秘、最佳实践及其在Spark中的应用源码解析之Scala学习笔记-55
- Scala中隐式参数与隐式转换的联合使用实战详解及其在Spark中的应用源码解析之Scala学习笔记-51