簡體   English   中英

RxJava - 整合多個、無限的 Observable <List<T> &gt;?

[英]RxJava- Consolidating multiple, infinite Observable<List<T>>?

這是我正在處理的一個有趣的 RxJava 小謎題。 假設我有一個Observable<List<Parent>> infiniteParentListStream是無限的,每個Parent都有一個Observable<List<Child>> infiniteChildListStream屬性,它也是無限的。

我想獲取發出的List<Parent>中的所有Parent實例,並將它們發出的每個List<Child>項目合並為一個完整的List<Child>反映所有父項的所有子項。

事實上, ParentObservable<List<Child>> infiniteChildListStream屬性是無限的,這使得toList()任務有點挑戰。

public final class NestedInfiniteTest {

    private static final BehaviorSubject<Integer> parentSubject = BehaviorSubject.create(1);
    private static final BehaviorSubject<Integer> childSubject = BehaviorSubject.create(1);

    public static void main(String[] args) {


        Observable<List<Parent>> infiniteParentListStream = parentSubject
                .map(i -> Arrays.asList(new Parent(), new Parent(), new Parent()))
                .cache(1);

        Observable<List<Child>> allCurrentChildren = infiniteParentListStream.<List<Child>>flatMap(parentList ->
                Observable.from(parentList)
                        .flatMap(p -> p.getInfiniteChildListStream().flatMap(Observable::from)).toList()
        ).cache(1);

        allCurrentChildren.subscribe(cl -> System.out.println("WHOLE CHILD LIST SIZE: " + cl.size()));
    }

    private static final class Parent {
        private final Observable<List<Child>> infiniteChildListStream = childSubject
                .map(i -> Arrays.asList(new Child(), new Child(), new Child())).cache(1);

        public Observable<List<Child>> getInfiniteChildListStream() {
            return infiniteChildListStream;
        }
    }
    private static final class Child {

    }
}

當然,我找到的一種解決方法是通過調用first()來將infiniteChildListStream變為有限。 但這並不理想,因為它不再更新。

Observable<List<Child>> allCurrentChildren = infiniteParentListStream.<List<Child>>flatMap(parentList ->
        Observable.from(parentList)
                .flatMap(p -> p.getInfiniteChildListStream().first().flatMap(Observable::from)).toList()
).cache(1);

我覺得有一種方法可以手動調用Observable.create()或使用flatMap()技巧來解決這個問題。 有沒有更好的方法來做到這一點並使事物與無限源保持反應? 在我這個 SSCCE 之外的實際應用程序中,這些 observables 是無限的,因為驅動ParentChild的數據源可能會改變並發出新的值......

我想我的問題的根源是如何獲取多個無限Observable<List<T>>並將它們合並為一個Observable<List<T>>

我想我是通過使用Observable.combineLatest()弄清楚的。 為了增強測試,我還修改了源 observables 以根據主題的推送整數值創建不同的List大小。 這看起來很漂亮。

public final class NestedInfiniteTest {

    private static final BehaviorSubject<Integer> parentSubject = BehaviorSubject.create(1);
    private static final BehaviorSubject<Integer> childSubject = BehaviorSubject.create(1);

    public static void main(String[] args) {

        Observable<List<Parent>> infiniteParentListStream = parentSubject
                .map(i -> IntStream.range(0,i).mapToObj(val -> new Parent()).collect(Collectors.toList()))
                .cache(1);

        Observable<List<Child>> allCurrentChildren = infiniteParentListStream.flatMap(parentList ->
                Observable.<Observable<List<Child>>>create(s -> {
                    parentList.stream().map(Parent::getInfiniteChildListStream).forEach(s::onNext);
                    s.onCompleted();
                })
                .toList() //List<<Observable<List<Child>>>>
                .flatMap(consolidatedChildList -> Observable.combineLatest(consolidatedChildList, new FuncN<List<Child>>() {
                    @Override
                    public List<Child> call(Object... args) {
                        ArrayList<Child> list = new ArrayList<>();
                        for (Object obj : args) {
                            list.addAll((List<Child>) obj);
                        }
                        return list;
                    }
                }))
        );


        allCurrentChildren.subscribe(cl -> System.out.println("WHOLE CHILD LIST SIZE: " + cl.size()));
        childSubject.onNext(10);
        parentSubject.onNext(5);
        childSubject.onNext(2);
    }

    private static final class Parent {
        private final Observable<List<Child>> infiniteChildListStream = childSubject
                .map(i -> IntStream.range(0, i).mapToObj(val -> new Child()).collect(Collectors.toList())).cache(1);

        public Observable<List<Child>> getInfiniteChildListStream() {
            return infiniteChildListStream;
        }
    }
    private static final class Child {

    }
}

輸出:

WHOLE CHILD LIST SIZE: 1   //parentSubject = 1, childSubject = 1
WHOLE CHILD LIST SIZE: 10  //parentSubject = 1, childSubject = 10
WHOLE CHILD LIST SIZE: 50  //parentSubject = 5, childSubject = 10
WHOLE CHILD LIST SIZE: 2   //parentSubject = 5, childSubject = 2, adjusting
WHOLE CHILD LIST SIZE: 42  //adjusting
WHOLE CHILD LIST SIZE: 34  //adjusting
WHOLE CHILD LIST SIZE: 26  //adjusting
WHOLE CHILD LIST SIZE: 18  //adjusting
WHOLE CHILD LIST SIZE: 10  //parentSubject = 5, childSubject = 2, done!

更新:創建了一個變壓器來執行這個任務

public static class CombinedListTransformer<T,R> implements Observable.Transformer<List<T>,List<R>> {

    private final Func1<T,Observable<List<R>>> listMapper;

    public CombinedListTransformer(Func1<T,Observable<List<R>>> listMapper) {
        this.listMapper = listMapper;
    }
    @Override
    public Observable<List<R>> call(Observable<List<T>> sourceList) {
        return sourceList.flatMap(sl ->
            Observable.from(sl).map(t -> listMapper.call(t)).toList() //List<Observable<List<R>>
            .flatMap(consolidatedChildList -> Observable.combineLatest(consolidatedChildList, args -> {
                ArrayList<R> list = new ArrayList<>();
                for (Object obj : args) {
                    list.addAll((List<R>) obj);
                }
                return list;
            }))
        );
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM