我使用RxJava
和Retrofit
来创建应用,我有这样的场景,在我的视图中,项目列表从服务器加载并显示给用户。用户可以通过单击刷新按钮刷新数据。以下是使用MVP的我的场景的粗略实现。
// This is my retrofit adapter service
public interface ApiService{
@GET("items");
Observable<JsonElement> getItemsList();
}
// This is my presnter
public class MyPresnter{
...
public Observable<List<Item>> loadItemsList(){
return apiService.getItemsList().map(jsonElement -> {
// here I convert my api response to a List of Items
return new ArrayList<Item>();
});
}
}
// And inside my view I use RxBinding to bind my button click events
RxView.clicks(refreshBtn).subscribe(view -> mPresenter.loadItemsList()
.subscribeOn(Schdulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(list -> {/* update view */})
);
现在我的问题是,当用户第一次进入视图时,如何在不点击refreshBtn
的情况下请求数据?我应该使用refreshBtn.performOnClick()
吗?
或者有没有办法在已订阅的observable上手动请求事件?
答案 0 :(得分:3)
如果您事先设置了performOnClick
,我猜您可以致电RxView.clicks()
。
通常,您可能希望合并Subject
也可以触发操作:
PublishSubject<Object> manualRefresh = PublishSubject.create();
RxView.clicks(refreshBtn)
.cast(Object.class)
.mergeWith(manualRefresh.onBackpressureLatest())
.switchMap(v -> mPresenter.loadItemsList()
.subscribeOn(Schdulers.io())
.observeOn(AndroidSchedulers.mainThread())
)
.subscribe(list -> /* update */);
manualRefresh.onNext("Now!");
答案 1 :(得分:3)
要回答这个问题,我们需要质疑流的逻辑。通常不良做法在前一个订阅方法中订阅新的observable。可能存在可能没有更好方法的情况,但至少是调查的迹象。流的组成是RxJava的最大优势之一。
这里的逻辑表明存在一系列事件(点击和手动调用),您希望对订阅另一个流做出反应。有一个运算符具有称为flatMap
的这种确切行为。
感谢flatMap
运营商,我们已经有办法在 发生时做出反应:
refreshEventStream
.flatMap(object -> {
return mPresenter.loadItemsList().subscribeOn(Schdulers.io())
})
.subscribe(list -> /* update UI */)
现在,我们需要弄清楚 某些 实际代表什么。如您所述,目前有两种方法可以调用刷新。通过点击事件和手动刷新。换句话说,我们希望将 合并 这些事件合并为一个流。同样,我们可以使用一个名为mergeWith
的漂亮而有光泽的运算符。但是,对于手动调用,我们需要创建Subject(http://reactivex.io/documentation/subject.html),它既可以作为Observable,也可以作为订阅者。
PublishSubject<Void> refreshSubject = PublishSubject.create()
refreshEventStream = refreshSubject
.mergeWith(Rx.clicks(refreshBtn).throttleFirst(500, TimeUnit.MILLISECONDS))
refreshEventStream
.flatMap(object -> {
return mPresenter.loadItemsList().subscribeOn(Schdulers.io())
})
.subscribe(list -> /* update UI */)
我在点击流中添加了throttleFirst
运算符,因为您可能不想让用户垃圾邮件包含以下请求:-)它唯一能做的就是从该流中获取一个事件并且在再次对其作出反应之前,将其余的排放量忽略一段时间。