@GET("/user/{id}/photo")
void getUserPhoto(@Path("id") int id, Callback<Photo> cb);
@GET("/user/{id}/photo")
Observable<Photo> getUserPhoto(@Path("id") int id);
而使用简单的回调实现则类似于如下所示:
api.getUserPhoto(photoId, new Callback<Photo>() {
@Override
public void onSuccess() {
}
});
这是非常简单和直接的。使用observable
,它很快就变得冗长和复杂。
public Observable<Photo> getUserPhoto(final int photoId) {
return Observable.create(new Observable.OnSubscribeFunc<Photo>() {
@Override
public Subscription onSubscribe(Observer<? super Photo> observer) {
try {
observer.onNext(api.getUserPhoto(photoId));
observer.onCompleted();
} catch (Exception e) {
observer.onError(e);
}
return Subscriptions.empty();
}
}).subscribeOn(Schedulers.threadPoolForIO());
}
但事实并非如此。你还是要做这样的事情:
Observable.from(photoIdArray)
.mapMany(new Func1<String, Observable<Photo>>() {
@Override
public Observable<Photo> call(Integer s) {
return getUserPhoto(s);
}
})
.subscribeOn(Schedulers.threadPoolForIO())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Photo>() {
@Override
public void call(Photo photo) {
//save photo?
}
});
我是不是漏了什么?还是使用observable
s是一个错误的情况?什么时候/应该更喜欢observable
而不是简单回调?
正如@Niels在他的答案中或在Jake Wharton的示例项目U2020中所示,使用改型比上面的示例简单得多。但本质上,问题是一样的--什么时候该用这样或那样的方法?
对于简单的网络材料,RxJava相对于回调的优势非常有限。简单的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) {
}
});
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);
}
}
}
});
第一个结论
当您加载一个简单的JSON时,它不会使您的代码库变小,因为您准备了正确的格式。
现在,让我们把事情变得更有趣一些。假设您不仅想要检索userPhoto,而且有一个Instagram-克隆,并且想要检索2个JSONs:1。getUserDetails()2。getUserPhotos()
您希望并行加载这两个JSON,当这两个JSONs都加载时,应该会显示页面。回调变体会变得更难一点:你要创建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只需要一个微小的调整,而回调变量需要在多个地方进行调整(在每次回调时,我们需要检查是否检索到了所有数据)。
inputObservable.debounce(1, TimeUnit.SECONDS).subscribe(new Action1<String>() {
@Override
public void call(String s) {
// use Retrofit to create autocompletedata
}
});
我不会创建回调变量,但您会明白这是更多的工作。
结论:当数据以流形式发送时,RxJava表现得特别好。可观察的改型同时将所有元素推到流上。与回调相比,这本身并不是特别有用。但是,当流上有多个元素和不同的时间被推送,并且您需要做与时间相关的事情时,RxJava使代码的可维护性大大提高。
问题内容: 我知道他们两个都禁用了Nagle的算法。 我什么时候应该/不应该使用它们中的每一个? 问题答案: 首先,不是所有人都禁用Nagle的算法。 Nagle的算法用于减少有线中更多的小型网络数据包。该算法是:如果数据小于限制(通常是MSS),请等待直到收到先前发送的数据包的ACK,同时累积用户的数据。然后发送累积的数据。 这将对telnet等应用程序有所帮助。但是,在发送流数据时,等待A
问题内容: 在该类中,有两个字符串,和。 有什么不同?我什么时候应该使用另一个? 问题答案: 如果你的意思是和则: 用于在文件路径列表中分隔各个文件路径。考虑在上的环境变量。您使用a分隔文件路径,因此在上将是;。 是或用于拆分到特定文件的路径。例如在上,或
问题内容: 在集成我以前从未使用过的Django应用程序时,我发现了用于定义类中函数的两种不同方式。作者似乎非常有意地使用了它们。第一个是我自己经常使用的: 另一个是我不使用的,主要是因为我不知道何时使用它,以及什么用途: 在Python文档中,装饰器的解释如下: 类方法将类作为隐式第一个参数接收,就像实例方法接收实例一样。 所以我想指的是自己(而不是实例)。我不完全理解为什么会这样,因为我总是可
问题内容: 奇怪的是: 似乎或多或少被定义为。通过这种方式很容易产生错误: 一些fname意外地以else块结尾。修复很简单,我们应该改用它,但是从表面上看,这似乎是一种不错的pythonic方式,并且比“正确”的方式更具可读性。 由于字符串是不可变的,所以为什么字符串错误是什么技术细节?什么时候进行身份检查更好,什么时候进行平等检查更好? 问题答案: 据我所知,检查对象身份是否相等。由于没有强制
问题内容: 我看过各种文章,但我仍然不知道为什么不应该使用它。请让我知道您的想法。 问题答案: 我发现有必要在错误的设计中使用instanceof提示。可以肯定的是,将会出现一个大型,复杂的开关风格的构造。在我看到的其他大多数情况下,我们应该使用多态而不是instanceof。请参阅策略模式。(相关的使用示例) 我唯一需要使用的是实现时。
问题内容: 我在阅读《 Swift编程语言》指南 时遇到了一个叫做的函数,但我仍然想知道为什么以及何时需要实现它,因为我们实际上不需要管理内存。 问题答案: 不需要实现该方法,但是如果需要在取消分配对象之前进行一些操作或清理,则可以使用它。 在苹果的文档包括例如: 因此,无论何时将玩家从游戏中移除,其硬币都会退还至银行。