Batch loading з Retrofit і RxJava

Доброго часу доби! Працюючи над одним проектом, виявив, що через зв'язку retrofit2 і retrofit2 adapter-rxjava не можна реалізувати batch loading в одному потоці.

Наведу приклад. Маємо опис retrofit-сервісу:

interface Api {
@GET("query.json")
Вами<List<SomeEntityServerView>> getAll(
@Query("first") int first, 
@Query("max") int batchSize);
}

Завантаження одного пакету:

service.getAll(0,20).map(list -> ...).observeOn(...).subscribe(...);

Для завантаження всіх сутностей з сервера, нам доведеться кожного разу створювати новий вами для завантаження чергового пакету. Крім того, як запхнути всі ці observable'и в один потік, представляється вкрай складним.

Для вирішення цієї проблеми, пропоную досить простий підхід.

public class BatchLoadingUtils {

/**
* @param batchLoaderFactory - метод створення обсервабла за номером першого елемента
* @param batchSize - розмір пакета
*/
public static <T> Вами<List<T>> create(Func1<Integer, Вами<List<T>>> batchLoaderFactory, int batchSize) {
//Тут зберігаємо номер першого елемента в пакеті
AtomicInteger first = new AtomicInteger(0);
//Сюди будемо цей номер відправляти. Відповідно, перший номер - 0. При бажанні, можна винести його параметри методу
BehaviorSubject<Integer> subject = BehaviorSubject.create(0);

return subject
//Перетворюємо змішання в вами
.flatMap(batchLoaderFactory::call)
.doOnNext(ts -> {
if (ts.size() == batchSize) {
//Якщо завантажили очікувана кількість елементів, вантажимо далі
subject.onNext(first.addAndGet(batchSize));
} else {
//В іншому - завершуємо роботу
subject.onCompleted();
}
});
}
}

Приклад використання:

final int batchSize = 10;
BatchLoader
.create(
first -> retrofitService.getAll(first, batchSize),
batchSize
)
.observeOn(Schedulers.computation())
.flatMapIterable(list -> list)
.map(TimeEntryServerView::buildTimeEntry)
.buffer(batchSize)
.subscribe(...);

Таким чином, ми отримали досить простий і ефективний спосіб вантажити пакети через ретрофит в зв'язці з RxJava. Гуру RxJava, напевно, зможуть запропонувати більш правильний підхід, у відповідності з усіма концепціями реактивного програмування і RxJava, проте, такий спосіб, однозначно, буде зрозумілий усім, хто хоч трохи знайомий з rx.

p.s. Пинайте сильно, це мій перший пост.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.