Flutter Streambuilder stuck in connectionstate.waiting

huangapple go评论59阅读模式
英文:

Flutter Streambuilder stuck in connectionstate.waiting

问题

我有一个关于Flutter应用程序的问题。我想通过Firebase Firestore按Document id接收数据。问题是,我无法在一个集合中复制数据,所以我必须使用两个集合。

我的数据是一个Measurement(String,String,...,List
MeasurementData(String,String,Number)

据我了解Firestore,我不能在一个集合中制作这样的列表,所以我创建了第二个集合,其中每个文档由三个数组组成。我还保存了Measurement文档的id。为了在Flutter中使用它,我使用了StreamBuilder小部件。为了更容易访问,我在使用文档之前将其转换为Dart对象。因为我有两个要转换为一个对象的流,我有一个先行流StreamMeasurement对象,它基本上与Measurement对象相同,但没有MeasurementData列表,因为这需要首先创建,而只保存了MeasurementData文档的id。之后,我使用Rx.zip2从StreamMeasurement对象创建一个Measurement对象,并添加List以获得一个完整的对象。

Class Service

/// Firebase实例
FirebaseFirestore db = FirebaseFirestore.instance;

/// 通过其id查找并返回[Measurement]
Stream<Measurement> getById(String id) {
    Stream<StreamMeasurement> streamMeasurementStream = db.collection("measurements").doc(id)
        .snapshots().map((document) => StreamMeasurement.fromJson(document.data()!));
    return Rx.zip2(streamMeasurementStream, getMeasurementDataStreamById(id),
        (StreamMeasurement streamMeasurement, List<MeasurementData> measurementData) {
            Measurement measurement = Measurement.fromStreamMeasurement(streamMeasurement, measurementData);
            if (measurement == null) {
                // TODO 写一个具体的异常来抛出和捕捉
                throw Exception('Measurement Stream is null');
            }
            return measurement;
        });
}

/// 为给定的Measurement id返回[Stream<List<MeasurementData>>]
Stream<List<MeasurementData>> getMeasurementDataStreamById(String id) {
    return db.collection("measurementData").where("measurement", isEqualTo: id)
        .snapshots()
        .map((querySnapshot) => querySnapshot.docChanges)
        .expand((changes) => changes)
        .map((change) => change.doc).map((document) => MeasurementData.fromJson(document.data()!));
}

Class DetailScreen

@override
Widget build(BuildContext context) {
    MeasurementService measurementService = MeasurementService();
    Stream<Measurement> measurementstream = measurementService.getById(
        "GmfzveKeozkcfdlrk75s");
    return StreamBuilder<Measurement>(
        stream: measurementstream,
        builder: (BuildContext context, AsyncSnapshot<Measurement> snapshot) {
            if (snapshot.hasError) {
                print(snapshot.error);
                return Text('出错了' + snapshot.error.toString());
            }

            if (snapshot.connectionState == ConnectionState.waiting) {
                print(snapshot);
                return Text("加载中" + snapshot.connectionState.toString());
            }
            Measurement? measurement = snapshot.data;
            return SafeArea(/*你的Widget代码*/);
        });
}

打印(snapshot) => I/flutter (19335): AsyncSnapshot(ConnectionState.waiting, null, null, null)

结果是,如果我使用getById(id)函数,StreamBuilder会停留在ConnectionState.waiting状态。

英文:

i have a problem with a Flutter application.
I want to receive data from a firebase firestore by an Document id.
The problem is, i cant replicate the data in one collection, so i have to use two collections.

My data ist a Measurement(String, String,..., List<MeasurementData>)
MeasurementData(String,String,Number)

As far as i understand the Firestore i cant make such a list in one collection, so i have created a second one in whitch each document consists of three arrays. I also save the id from the Measurement Document where it belongs to.
To use it in Flutter a use a StreamBuilder widget. For easer access i convert the document bevor using into a Dart Object. Because i have two Streams which should be converted to one Object i have a predessecor StreamMeasurement object which is basicly the same as the Measurement Object, but without the MeasurementData list, because this first needs to be created, instead it only saves a id for the measurementData Document.
After that i use the Rx.zip2 to create an Measurement Object from the StreamMeasurement Object and add the List<MeasurementData> to have a complete object.

    Class Service
    
    /// The firebase instance
    FirebaseFirestore db = FirebaseFirestore.instance;
    
    ///Finds and returns a [Measurement] by its [id]
    Stream&lt;Measurement&gt; getById(String id) {
    Stream&lt;StreamMeasurement&gt; streamMeasurementStream =db.collection(&quot;measurements&quot;).doc(id)
         .snapshots().map((document) =&gt; StreamMeasurement.fromJson(document.data()!));
    return Rx.zip2(streamMeasurementStream, getMeasurementDataStreamById(id)
            , (StreamMeasurement streamMeasurement, List&lt;MeasurementData&gt; measurementData) {
                  Measurement measurement = Measurement.fromStreamMeasurement(streamMeasurement, measurementData);
                  if(measurement == null)
                  {
                      //TODO Write a concrete exception to throw and catch
                      throw Exception(&#39;Measurement Stream is null&#39;);
                  }
                  return measurement;
          }) ;
      }

     /// Returns a [Stream&lt;List&lt;MeasurementData&gt;&gt;] for a given Measurement id
    Stream&lt;List&lt;MeasurementData&gt;&gt; getMeasurementDataStreamById(String id)
      {
        return db.collection(&quot;measurementData&quot;).where(&quot;measurement&quot;, isEqualTo: id).
         snapshots().
         map((querySnapshot) =&gt; querySnapshot.docChanges)
        .expand((changes) =&gt; changes)
        .map((change) =&gt; change.doc).map((document) =&gt; MeasurementData.fromJson(document.data()!));
       }

    Class DetailScreen
    @override
    Widget build(BuildContext context) {
        MeasurementService measurementService = MeasurementService();
        Stream&lt;Measurement&gt; measurementstream = measurementService.getById(
        &quot;GmfzveKeozkcfdlrk75s&quot;);
        return StreamBuilder&lt;Measurement&gt;(
            stream: measurementstream,
            builder: (BuildContext context, AsyncSnapshot&lt;Measurement&gt; snapshot) {
            if (snapshot.hasError) {
                print(snapshot.error);
                return Text(&#39;Something went wrong&#39; + snapshot.error.toString());
            } 

            if (snapshot.connectionState == ConnectionState.waiting) {
               print(snapshot);
               return Text(&quot;Loading&quot; + snapshot.connectionState.toString());
             }
             Measurement? measurement = snapshot.data;
             return SafeArea(

Print(snapshot) => I/flutter (19335): AsyncSnapshot<Measurement>(ConnectionState.waiting, null, null, null)

The result is, that the StreamBuilder is stuck in ConnectionState.waiting state if i use the getById(id) function

答案1

得分: -1

问题已解决。问题出在ID前有一个不匹配的空格。
编辑:我在数据库中手动硬编码了ID,写的时候在ID前留下了一个空格,这个空格不应该存在,所以请求无法正常工作,应该是"1234"而不是" 1234"。

英文:

Okay, ... Question solved. The problem was a unmatched whitespace before the id
EDIT: I had hardcodet the ID manually in the database, while writing i had left an whitespace before id, that doesnt belongs there and so the request doesnt work like " 1234" should be "1234"

huangapple
  • 本文由 发表于 2023年2月18日 01:49:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/75487672.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定