您的位置:首页 > 其它

Retrofit源码学习笔记(2)-CallAdapter解析

2017-01-11 22:00 477 查看
Retrofit允许各种第三方库来对返回的HTTP call进行操作。因此这就要求Retrofit给出一套机制来使得API 请求和现有的第三库进行无缝的链接。这个机制就是CallAdapter,它可以将返回的 http call进行处理,从而适应不同的操作。

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Retrofit callAdapte 源码
相关文章推荐