用例:有一个POJO类的数据集。在这种情况下,它是ArrayList
。我创建了一个类,它扩展了ArrayList
并提供了一些帮助程序方法,该方法将列表分为页面。页面仅将列表分成小页面,以上传到REST API。我从Iterable
创建了一个Iterator
,该工具检查页面是否可用于上传,然后获取该页面。该页面需要上传,并且一旦上传成功,它将被删除,然后再次需要下一页。此过程必须继续从列表中连续上传每个页面,直到页面为空。
代码:(此处模拟了API调用)
import io.reactivex.Completable;
import io.reactivex.Flowable;
import io.reactivex.schedulers.Schedulers;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Sample {
public static void main(String[] args) {
Store store = new Store();
for (int i = 0; i < 20; i++)
store.add("Sample value");
store.getPageStream()
.flatMapCompletable(in -> getApi().doOnComplete(store::removePage))
.subscribe(() -> System.out.println("Job done"), Throwable::printStackTrace);
}
private static Completable getApi() {
return Completable.create(emitter -> {
System.out.println("API Requesting");
Thread.sleep(2000);
System.out.println("API Done\n\n");
emitter.onComplete();
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
}
class Store extends ArrayList<String> {
private static final int PAGE_SIZE = 3;
private final Object pageLock = new Object();
private final Iterator<List<String>> iterator = new Iterator<List<String>>() {
@Override
public boolean hasNext() {
return isAvailable();
}
@Override
public List<String> next() {
return getPage();
}
};
private int lastPageSize = 0;
Flowable<List<String>> getPageStream() {
return Flowable.fromIterable(() -> iterator);
}
private List<String> getPage() {
synchronized (pageLock) {
List<String> temp = new ArrayList<>();
lastPageSize = Math.min(size(), PAGE_SIZE);
for (int i = 0; i < lastPageSize; i++)
temp.add(get(i));
return temp;
}
}
void removePage() {
synchronized (pageLock) {
if (lastPageSize <= 0)
return;
System.out.println(toString());
removeRange(0, lastPageSize);
lastPageSize = 0;
System.out.println(toString());
}
}
private boolean isAvailable() {
synchronized (pageLock) {
return size() > 0;
}
}
}
问题是:该过程不是连续发生的。 flatMapCompletable在请求下一页之前没有等待API完成。而且,由于它不断地请求页面而不删除它们,所以它永远不会完成。
其他信息::如果我从.subscribeOn(Schedulers.io())
方法中删除了行getApi()
,则调用会依次发生,并且效果很好,但会导致NetworkOnMainThreadException
在此先感谢您能解决这个问题。