在 Android 应用开发中采用 RxJava 架构时,网络请求是最常见的场景之一。通常结合 Retrofit 作为网络层,配合 HashMap 或 Room 进行缓存。
Retrofit 接口定义如下:
@GET("events")
Single<List<Event>> getEventsFeed(...);
通过 Repository 接口暴露,订阅方式如下:
Single<List<Event>> source = remoteRepository.getEventsFeed(...);
source
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(data -> {
// Do something with data e.g. pass it to view
}, throwable -> {
// Handle error e.g. show dialog
});
RxJava 的优点在于可以将复杂的异步任务串联起来,而执行和观察结果的代码保持不变。以下是开发基本或中等复杂应用时会遇到的三种情形。
1. 从缓存或者网络获取数据
如果有缓存则从缓存中取值,否则从网络获取。
Maybe<List<Event>> source1 = cacheRepository.getEventsFeed(...);
Single<List<Event>> source2 = networkRepository.getEventsFeed(...);
Maybe<List<Event>> source = Maybe.concat(source1, source2.toMaybe()).firstElement();
这里使用 concat 操作符将两个 Observable 连接在一起,firstElement 意味着只关心第一个发射出来的值。如果缓存有值,该值会被发射并调用 onCompleted,网络请求不会被调用。如果缓存没有值,网络请求将会发生。使用 Maybe 暗示着观察不到值的可能,例如缓存为空且网络也没有返回结果。
2. 发起两个请求,第二个请求依赖于第一个
从网络上取值并使用其部分结果发起另外一个网络请求来获取真正想要的数据。
Single<User> source1 = networkRepository.getMyProfile(...);
Single<List<Tweet>> source = source1.flatMap(user -> {
return networkRepository.getUserTweets(user.getTwitterId());
});
3. 同时发起多个请求,并结合他们的结果
有三个网络请求互不依赖,想同时执行以提高响应时间。等到三个请求都结束后才发射值。
Single<List<Event>> source1 = networkRepository.getEventsFeed(...);
Single<List<Bookmark>> source2 = networkRepository.getBookmarks(...);
Single<Stats> source3 = networkRepository.getUserStats(...);
Single<MyViewModel> source = Single.zip(source1, source2, source3, MyViewModel::new);
这个例子中使用 zip 操作符来合并这三个 Observables,它们被结合为一个 MyViewModel 的 POJO。其构造参数与源 Observables 的类型匹配:
public MyViewModel(List<Event> events, List<Bookmark> bookmarks, Stats stats) { ... }
当你订阅这个源 Observable 时,将会同时发起三个网络请求,但是只有当它们都完成后才将新的 MyViewModel 实例发射出去。


