Open4
Flutter/Dartで複数のストリームを1つにまとめる
ピン留めされたアイテム
結論としては、次でできた。
import 'package:rxdart/rxdart.dart';
final mergedStream = Rx.combineLatest2(
fruitsStream,
vegetablesStream,
(List<String> a, List<String> b) => a + b,
);
// mergedStreamは2つのList<String>を束ねて次を出力する
// ['apple','banana','orange','carrot','radish','potate']
やりたかったことは、Firestoreが出力するStreamを束ねて1つにすること。
例えば、次のようなList<String>
を出力するStreamを束ねて1つにし、同じタイムラインに表示したかった。
import 'package:cloud_firestore/cloud_firestore.dart';
// ['apple','banana','orange']を出力
final fruitsStream = FirebaseFirestore.instance.collection('fruits').snapshots();
// ['carrot','radish','potate']を出力
final vegetablesStream = FirebaseFirestore.instance.collection('vegetables').snapshots();
// これらを束ねて、次を出力するStreamを作りたい
// ['apple','banana','orange','carrot','radish','potate']
当初はStreamの概念が掴めておらず、試行錯誤した。
例えば、試してダメだったのは、次のような束ね方。
import 'package:async/async.dart';
final mergedStream = StreamZip([fruitsStream,vegetablesStream]);
StreamZip
は各ストリームが出力する最新の値を、ペアとして出力していく。
つまり、fruitsStream
、vegetablesStream
をStreamZip
で束ねた場合、
mergedStream
// mergedStreamは次を順々に出力していく
// ['apple','carrot']
// ['banana','radish']
// ['orange','potate']
と、最終的にはタイムラインには ['orange','potate']
しか表示できない。
また、ペアを生成することを前提としているためか、どちらかのStreamがnull
(一つも要素が出力されない)だと、うまく処理できない部分があった。
StreamZip class - async library - Dart API
AsyncSnapshot class - widgets library - Dart API
あと、今回の目的だと次もダメだった。
final mergedStream = StreamGroup.merge([
fruitsStream,
vegetablesStream,
]);
StreamGroup.merge()
は、各Streamを束ねてSingle-Subscription Streamを作るため、
mergedStream
// mergedStreamは次を順々に出力していく
// ['apple','banana','orange']
// ['carrot','radish','potate']
と、後から出力された vegetablesStream
しか表示されない。
StreamGroup class - async library - Dart API
Dart 2 Language Guide