【发布时间】:2015-04-10 06:58:05
【问题描述】:
我几乎被卖给了 RxJava,它是 Retrofit 的完美伴侣,但我在迁移代码时遇到了一个常见的模式:为了节省带宽,我想从我的webservice 根据需要,而我的 listview(或 recyclerview)正在使用响应式编程滚动。
我之前的代码完美地完成了这项工作,但反应式编程似乎值得一试。
收听 listview/recyclerview 滚动(和其他无聊的东西)不是问题,使用 Retrofit 很容易获得 Observable:
@GET("/api/messages")
Observable<List<Message>> getMessages(@Path("offset") int offset, @Path("limit") int limit);
我只是想不出在反应式编程中使用的模式。
Concat 运算符似乎是一个很好的起点,在某些时候还可以使用 ConnectableObservable 来延迟发射,也许还有 flatMap,但是如何?
编辑:
这是我目前(幼稚)的解决方案:
public interface Paged<T> {
boolean isLoading();
void cancel();
void next(int count);
void next(int count, Scheduler scheduler);
Observable<List<T>> asObservable();
boolean hasCompleted();
int position();
}
以及我使用主题的实现:
public abstract class SimplePaged<T> implements Paged<T> {
final PublishSubject<List<T>> subject = PublishSubject.create();
private volatile boolean loading;
private volatile int offset;
private Subscription subscription;
@Override
public boolean isLoading() {
return loading;
}
@Override
public synchronized void cancel() {
if(subscription != null && !subscription.isUnsubscribed())
subscription.unsubscribe();
if(!hasCompleted())
subject.onCompleted();
subscription = null;
loading = false;
}
@Override
public void next(int count) {
next(count, null);
}
@Override
public synchronized void next(int count, Scheduler scheduler) {
if (isLoading())
throw new IllegalStateException("you can't call next() before onNext()");
if(hasCompleted())
throw new IllegalStateException("you can't call next() after onCompleted()");
loading = true;
Observable<List<T>> obs = onNextPage(offset, count).single();
if(scheduler != null)
obs = obs.subscribeOn(scheduler); // BEWARE! onNext/onError/onComplete will happens on that scheduler!
subscription = obs.subscribe(this::onNext, this::onError, this::onComplete);
}
@Override
public Observable<List<T>> asObservable() {
return subject.asObservable();
}
@Override
public boolean hasCompleted() {
return subject.hasCompleted();
}
@Override
public int position() {
return offset;
}
/* Warning: functions below may be called from another thread */
protected synchronized void onNext(List<T> items) {
if (items != null)
offset += items.size();
loading = false;
if (items == null || items.size() == 0)
subject.onCompleted();
else
subject.onNext(items);
}
protected synchronized void onError(Throwable t) {
loading = false;
subject.onError(t);
}
protected synchronized void onComplete() {
loading = false;
}
abstract protected Observable<List<T>> onNextPage(int offset, int count);
}
【问题讨论】:
-
我希望有一个 observable 在必须获取新消息时发出事件,即到达页面底部。然后,您可以为这个 observable 订阅一个函数,以获取每个事件的消息并将它们附加到页面。
-
@nono240 :在阅读 lopar 的答案之前,我最终得到了一些“概念上”类似于你所做的事情(基本上具有加载状态)。顺便说一句:我认为您可以将几个“loading = false”替换为集中的“finallyDo”(reactivex.io/documentation/operators/do.html)
-
@nono240 此外:运算符“withLatestFrom”(github.com/ReactiveX/RxJava/releases/tag/v1.0.7) 最近作为实验性发布,在这种情况下可能有用,我稍后会调查(我是 Rx 编程的新手,所以让我们看,也许根本没有意义!)
标签: android pagination reactive-programming rx-java