对于简单的网络事物,RxJava 相对于 Callback 的优势非常有限。简单的 getUserPhoto 示例:
RxJava:
api.getUserPhoto(photoId)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Photo>() {
@Override
public void call(Photo photo) {
// do some stuff with your photo
}
});
打回来:
api.getUserPhoto(photoId, new Callback<Photo>() {
@Override
public void onSuccess(Photo photo, Response response) {
}
});
RxJava 变体并不比 Callback 变体好多少。现在,让我们忽略错误处理。
我们来列出一张照片:
RxJava:
api.getUserPhotos(userId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.flatMap(new Func1<List<Photo>, Observable<Photo>>() {
@Override
public Observable<Photo> call(List<Photo> photos) {
return Observable.from(photos);
}
})
.filter(new Func1<Photo, Boolean>() {
@Override
public Boolean call(Photo photo) {
return photo.isPNG();
}
})
.subscribe(
new Action1<Photo>() {
@Override
public void call(Photo photo) {
list.add(photo)
}
});
打回来:
api.getUserPhotos(userId, new Callback<List<Photo>>() {
@Override
public void onSuccess(List<Photo> photos, Response response) {
List<Photo> filteredPhotos = new ArrayList<Photo>();
for(Photo photo: photos) {
if(photo.isPNG()) {
filteredList.add(photo);
}
}
}
});
现在,RxJava 变体仍然不小,尽管使用 Lambda 后它会更接近 Callback 变体。
此外,如果您有权访问 JSON feed,那么当您只显示 PNG 时检索所有照片会有点奇怪。只需将 feed 调整为仅显示 PNG 即可。
第一个结论
当您加载准备采用正确格式的简单 JSON 时,它不会使您的代码库变小。
现在,让我们让事情变得更有趣一些。假设您不仅想要检索 userPhoto,而且您有一个 Instagram 克隆,并且想要检索 2 个 JSON:
1. 获取用户详细信息()
2. 获取用户照片()
您想要并行加载这两个 JSON,并且当两者都加载时,应该显示页面。
回调变体将变得有点困难:您必须创建 2 个回调,将数据存储在活动中,如果加载了所有数据,则显示页面:
打回来:
api.getUserDetails(userId, new Callback<UserDetails>() {
@Override
public void onSuccess(UserDetails details, Response response) {
this.details = details;
if(this.photos != null) {
displayPage();
}
}
});
api.getUserPhotos(userId, new Callback<List<Photo>>() {
@Override
public void onSuccess(List<Photo> photos, Response response) {
this.photos = photos;
if(this.details != null) {
displayPage();
}
}
});
RxJava:
private class Combined {
UserDetails details;
List<Photo> photos;
}
Observable.zip(api.getUserDetails(userId), api.getUserPhotos(userId), new Func2<UserDetails, List<Photo>, Combined>() {
@Override
public Combined call(UserDetails details, List<Photo> photos) {
Combined r = new Combined();
r.details = details;
r.photos = photos;
return r;
}
}).subscribe(new Action1<Combined>() {
@Override
public void call(Combined combined) {
}
});
我们正在取得进展! RxJava 的代码现在和回调选项一样大。 RxJava代码更加健壮;
想想如果我们需要加载第三个 JSON(如最新的视频)会发生什么? RxJava 只需要进行微小的调整,而 Callback 变体需要在多个位置进行调整(在每个回调上,我们需要检查是否检索到所有数据)。
另一个例子;我们想要创建一个自动完成字段,它使用 Retrofit 加载数据。
我们不想在每次 EditText 有 TextChangedEvent 时都进行网络调用。快速打字时,只有最后一个元素应该触发调用。
在 RxJava 上我们可以使用 debounce 运算符:
inputObservable.debounce(1, TimeUnit.SECONDS).subscribe(new Action1<String>() {
@Override
public void call(String s) {
// use Retrofit to create autocompletedata
}
});
我不会创建回调变体,但您会明白这是更多的工作。
结论:
当数据作为流发送时,RxJava 表现得非常好。 Retrofit Observable 同时推送流上的所有元素。
与回调相比,这本身并不是特别有用。但是,当有多个元素在不同时间推送到流上时,并且您需要执行与计时相关的操作,RxJava 使代码更易于维护。