New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
StreamBuilder doesn't support merged streams #23173
Comments
Try https://pub.dartlang.org/packages/rxdart to find out ways about combining streams in powerful ways. |
Please consider asking support questions in one of the other channels listed at http://flutter.io/support . There is no difference in normal or merged streams. The issue has to be caused by something else. |
Dup of dart-lang/async#70 |
I saw that dart-lang/async#70 was also closed. |
The merged streams did print the expected output to the console when accessed from outside the streambuilder , however when the StreamBuilder's snapshot ignores the first item in the stream and only updates the UI about the second item.
|
Perhaps the widget is rebuilt and |
Sample app: import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:rxdart/rxdart.dart' show Observable;
import 'dart:async';
final String TAG = "StreamBuilderTest.Flutter";
String _searchQuery = "vegan yoga";
class A extends StatefulWidget{
@override
State createState() => Astate();
}
class Astate extends State{
@override
Widget build(BuildContext context){
return Scaffold(body: StreamBuilder(stream: searchResult(), builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot){
if(!snapshot.hasData){
return Text("loading....");
}
int length = snapshot.data.documents.length;
//print("from the streamBuilder: "+ snapshot.data.documents[]);
print(length.toString()+ " doc length");
return ListView.builder(
itemCount: length,
itemBuilder: (_,int index){
final DocumentSnapshot doc = snapshot.data.documents[index];
//print(doc.data["name"].toString());
return new Container(child: Text(doc.data["name"]));
},
);
},
),);
}
Stream<QuerySnapshot> searchResult() {
List<String> queryKeys = _searchQuery.split(" "); //the length of this should not be big I should assert but I wont for now TODO to improve latency
CollectionReference firestoreCollection = Firestore.instance.collection("activities");
List<Stream<QuerySnapshot>> streamList = [];
for (int i =0 ; i <queryKeys.length; i++ ){
try{
Stream<QuerySnapshot> x = firestoreCollection.where("query", arrayContains: queryKeys[i]).snapshots();
streamList.add(x);
print(TAG + "added a stream "+queryKeys[i] );
} catch(e){print(TAG+" error on query keyword search"+e.toString());
}
}
var x = Observable.merge(streamList);
//this test shows that the stream gets contents from both qury streams
// x.map((convert){ convert.documents.forEach((f){print(f.data["name"]);});}).listen(print);
return x;
}
}
void main(){runApp(MaterialApp(home:A()));
} |
I think what the problem here is that each stream emits an event when the response from Firebase arrives, where the data is a collection of entries. Flutter/StreamBuilder first causes the data from the first event to render, then when the 2nd event arrives the widget is rebuilt with the data from the 2nd event. The import 'package:flutter/material.dart';
import 'package:rxdart/rxdart.dart' show Observable;
import 'dart:async';
class A extends StatefulWidget {
@override
State createState() => AState();
}
class AState extends State<A> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder(
stream: searchResult(),
builder: (BuildContext context, AsyncSnapshot<List<String>> snapshot) {
if (!snapshot.hasData) {
return Text("loading....");
}
int length = snapshot.data.length;
//print("from the streamBuilder: "+ snapshot.data.documents[]);
print(length.toString() + " doc length");
return ListView.builder(
itemCount: length,
itemBuilder: (_, int index) {
final String doc = snapshot.data[index];
//print(doc.data["name"].toString());
return new Container(child: Text(doc));
},
);
},
),
);
}
Stream<List<String>> searchResult() {
List<Stream<List<String>>> streamList = [];
for (int i = 0; i < 3; i++) {
try {
streamList.add(
Observable<List<String>>.just(
[
'${i}_1',
'${i}_2',
'${i}_3',
],
).delay(Duration(seconds: i * 2)),
);
} catch (e) {}
}
var x = Observable.merge(streamList).scan<List<String>>((acc, curr, i) {
return acc ?? <String>[]
..addAll(curr);
});
//this test shows that the stream gets contents from both query streams
// x.map((convert){ convert.documents.forEach((f){print(f.data["name"]);});}).listen(print);
return x;
}
}
void main() {
runApp(MaterialApp(home: A()));
}
|
A work around that worked for me is using a listview builder , and attaching a stream listener in initState @OverRide } |
I think it would be a good idea to move this code out of Flutter widgets. |
I settled on a work around that uses StreamZip and list manipulation with the StreamBuilder
|
Any new solution since RxDart doesn't have Observable since 0.23.1 |
@zoechi the problem with |
Kindly suggest what is the issue in the code, mentioned at https://stackoverflow.com/questions/68000556/how-to-merge-2-firestore-queries-steams-in-flutter-dart |
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of |
When trying to merge query streams the SteamBuilder only shows the second stream, my guess is that this issue has to do with Dart stream combining streams as the StreamBuilder widget seems to work correctly, nonetheless, this issue is a major one as it prevents flutter developers from combining queries an important feature for any app that uses an API.
I already tracked the issue in DartLang but I felt that I should address it here as well as maybe a flutter widget can address the issue.
dart-lang/async#70
The text was updated successfully, but these errors were encountered: