Retrofit 除了提供了传统的 Callback 形式的 API,还有 RxJava 版本的 Observable 形式 API。下面我用对比的方式来介绍 Retrofit 的 RxJava 版 API 和传统版本的区别。php
以获取一个 User 对象的接口做为例子。使用Retrofit 的传统 API,你能够用这样的方式来定义请求:java
@GET("/user")
public void getUser(@Query("userId") String userId, Callback<User> callback);
1
2
在程序的构建过程当中, Retrofit 会把自动把方法实现并生成代码,而后开发者就能够利用下面的方法来获取特定用户并处理响应:数据库
getUser(userId, new Callback<User>() {
@Override
public void success(User user) {
userView.setUser(user);
}编程
@Override
public void failure(RetrofitError error) {
// Error handling
...
}
};
1
2
3
4
5
6
7
8
9
10
11
12
而使用 RxJava 形式的 API,定义一样的请求是这样的:json
@GET("/user")
public Observable<User> getUser(@Query("userId") String userId);
1
2
使用的时候是这样的:设计模式
getUser(userId)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<User>() {
@Override
public void onNext(User user) {
userView.setUser(user);
}网络
@Override
public void onCompleted() {
}ide
@Override
public void onError(Throwable error) {
// Error handling
...
}
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
看到区别了吗?函数式编程
当 RxJava 形式的时候,Retrofit 把请求封装进 Observable ,在请求结束后调用 onNext() 或在请求失败后调用 onError()。函数
对比来看, Callback 形式和 Observable 形式长得不太同样,但本质都差很少,并且在细节上 Observable 形式彷佛还比 Callback 形式要差点。那 Retrofit 为何还要提供 RxJava 的支持呢?
由于它好用啊!从这个例子看不出来是由于这只是最简单的状况。而一旦情景复杂起来, Callback 形式立刻就会开始让人头疼。好比:
假设这么一种状况:你的程序取到的 User 并不该该直接显示,而是须要先与数据库中的数据进行比对和修正后再显示。使用 Callback 方式大概能够这么写:
getUser(userId, new Callback<User>() {
@Override
public void success(User user) {
processUser(user); // 尝试修正 User 数据
userView.setUser(user);
}
@Override
public void failure(RetrofitError error) {
// Error handling
...
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
有问题吗?
很简便,但不要这样作。为何?由于这样作会影响性能。数据库的操做很重,一次读写操做花费 10~20ms 是很常见的,这样的耗时很容易形成界面的卡顿。因此一般状况下,若是能够的话必定要避免在主线程中处理数据库。因此为了提高性能,这段代码能够优化一下:
getUser(userId, new Callback<User>() {
@Override
public void success(User user) {
new Thread() {
@Override
public void run() {
processUser(user); // 尝试修正 User 数据
runOnUiThread(new Runnable() { // 切回 UI 线程
@Override
public void run() {
userView.setUser(user);
}
});
}).start();
}
@Override
public void failure(RetrofitError error) {
// Error handling
...
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
性能问题解决,但……这代码实在是太乱了,迷之缩进啊!杂乱的代码每每不只仅是美观问题,由于代码越乱每每就越难读懂,而若是项目中充斥着杂乱的代码,无疑会下降代码的可读性,形成团队开发效率的下降和出错率的升高。
这时候,若是用 RxJava 的形式,就好办多了。 RxJava 形式的代码是这样的:
getUser(userId)
.doOnNext(new Action1<User>() {
@Override
public void call(User user) {
processUser(user);
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<User>() {
@Override
public void onNext(User user) {
userView.setUser(user);
}
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable error) {
// Error handling
...
}
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
其中
doOnNext()的执行在onNext()以前,对数据进行相关处理。doOnNext在哪个线程处理,暂时不明。
参考连接
RxJava操做符doOnNext - 享受技术带来的快乐! - 博客频道 - CSDN.NET
Rxjava中的doOnNext的做用和在哪里执行 - u010746364的博客 - 博客频道 - CSDN.NET
后台代码和前台代码全都写在一条链中,明显清晰了不少。
再举一个例子:假设 /user 接口并不能直接访问,而须要填入一个在线获取的 token ,代码应该怎么写?
Callback 方式,可使用嵌套的 Callback:
@GET("/token")
public void getToken(Callback<String> callback);
@GET("/user")
public void getUser(@Query("token") String token, @Query("userId") String userId, Callback<User> callback);
...
getToken(new Callback<String>() {
@Override
public void success(String token) {
getUser(token, userId, new Callback<User>() {
@Override
public void success(User user) {
userView.setUser(user);
}
@Override
public void failure(RetrofitError error) {
// Error handling
...
}
};
}
@Override
public void failure(RetrofitError error) {
// Error handling
...
}
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
却是没有什么性能问题,但是迷之缩进毁一辈子,你懂我也懂,作过大项目的人应该更懂。
而使用 RxJava 的话,代码是这样的:
@GET("/token")
public Observable<String> getToken();
@GET("/user")
public Observable<User> getUser(@Query("token") String token, @Query("userId") String userId);
...
getToken()
.flatMap(new Func1<String, Observable<User>>() {
@Override
public Observable<User> onNext(String token) {
return getUser(token, userId);
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<User>() {
@Override
public void onNext(User user) {
userView.setUser(user);
}
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable error) {
// Error handling
...
}
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
用一个 flatMap() 就搞定了逻辑,依然是一条链。看着就很爽,是吧?
RxJava配合Retrofit2.0使用
新的Retrofit2.0简直就是设计模式的教科书典范,同时对Rx的支持也更加友好,本例子为查询ip获取地理信息,并过滤掉失败信息
//使用Rxjava配合Retrofit解析json数据,注意这里全是电脑运行的,没有分开线程订阅
public static void main(String[] args) throws Exception{
OkHttpClient client = new OkHttpClient();
client.interceptors().add(new LoggingInterceptor());//log for okhttp
Retrofit retrofit = new Retrofit.Builder().baseUrl(IPService.END).client(client)
.addConverterFactory(GsonConverterFactory.create())//对Response进行adapter转换
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())//对转换后的数据进行再包装
.build();
retrofit.create(IPService.class)//动态代理生成class
//直接操做json数据,这里可不是一个好的习惯,真正应该是DTO对象的
.getIPInfo("58.19.239.11")
.filter(jsonObject -> jsonObject.get("code").getAsInt()==0)
//转换数据类型
.map(jsonObject1 -> jsonObject1.get("data"))
//输出结果
.subscribe(System.out::println);
}
//retrofit定义的接口
interface IPService {
String END = "http://ip.taobao.com";
//建议写成dto对象,博主只是为了演示filter就把这里JsonObject了
@GET("/service/getIpInfo.php") Observable<JsonObject> getIPInfo(@Query("ip") String ip);
}
/**
* Retrofit2.0已经把网络部分剥离了,因此须要本身实现Log
*/
static class LoggingInterceptor implements Interceptor {
@Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
long t1 = System.nanoTime();
System.out.println(
String.format("Sending request %s on %s%n%s", request.url(), chain.connection(),
request.headers()));
Response response = chain.proceed(request);
long t2 = System.nanoTime();
System.out.println(
String.format("Received response for %s in %.1fms%n%s", response.request().url(),
(t2 - t1) / 1e6d, response.headers()));
return response;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
源代码
rengwuxian RxJava Samples
参考连接
给 Android 开发者的 RxJava 详解