簡體   English   中英

為什么“等待”在 Firebase RTDB 中失敗?

[英]Why do "awaits" fail in Firebase RTDB?

我目前正在使用 Firebase RTDB 8.2 版,每次更新到 9.1 版時,我的應用程序中使用 await 的查詢都會遇到嚴重問題

基本上問題在於,從版本 9 開始,等待不能以可預測的方式工作。

我做了以下代碼來檢查它......

該代碼有一個查詢按鈕,按下時( _submit() )會顯示數據庫中的文章列表並返回數量總和的結果:

 Future<void> _submit() async {
   List<ItemModel> itemsList = [];
   itemsList = await loadItems();
   int _sumQty = itemsList.fold(0, (a, b) => a + b.quantity!);
   print('$_sumQty was the sum of quantities');
 }

如果此代碼與web 上的 Firebase 版本 8.2.0 一起使用,則結果如預期:

{項目:iPhone,數量:5} {項目:三星,數量:10} {項目:LG,數量:15} {項目:NTC,數量:20} {項目:Zenith,數量:25} {項目:索尼,數量:30} {項目:JVC,數量:40}

已加載 7 項

145 是數量的總和

如果在 Web 上使用最新版本的Firebase (9.1.4)相同的代碼,則結果完全錯誤:

{項目:iPhone,數量:5}

1 項目已加載

5 是數量的總和

{項目:三星,數量:10} {項目:LG,數量:15} {項目:NTC,數量:20} {項目:Zenith,數量:25} {項目:索尼,數量:30} {項目:JVC,數量:40}

請注意,在新版本中,如果您在代碼的某些部分中使用等待,則執行不會等待完整列表,而只會獲取導致混亂的第一個組件。

盡管錯誤在 Web 上 100% 發生,但這種情況也(最終)在移動設備(Android)上發生

問題是:

1. Firebase 的最新版本中改變 Await 行為的根源是什么?

2. 如果建議遷移到最新版本,應在代碼中進行哪些更改以確保查詢中不會出現這種意外行為?

附件 - FIREBASE 8.2.0 的完整代碼:

import 'package:firebase_database/firebase_database.dart';
import 'package:firebase_database/ui/firebase_list.dart';
import 'package:flutter/material.dart';
 
class Prueba extends StatefulWidget {
 const Prueba({Key? key}) : super(key: key);
 
 @override
 State<Prueba> createState() => _PruebaState();
}
 
class ItemModel {
   String? item;
   int? quantity;
 
   ItemModel({
       this.item,
       this.quantity,
   });
}
 
class _PruebaState extends State<Prueba> {
 
@override
 void dispose() {
   super.dispose();
 }
 
@override
void initState() {
 super.initState(); 
}
 
 @override
 Widget build(BuildContext context) {
 
   return Scaffold(
     appBar: AppBar(
       title: const Text('Async InitState Test'),
     ),
     body: createButton('Query'),
 
   );
 }
 
   Widget createButton(String texto) {
   return Container(
     width: double.infinity,
     padding: const EdgeInsets.only(top:30.0, left:10.0, right:10.0),
     child: ElevatedButton(
       onPressed: _submit,
       child: Text(texto, style: Theme.of(context).textTheme.headline6),
     ),
   );
 }
 
 Future<void> _submit() async {
   List<ItemModel> itemsList = [];
   itemsList = await loadItems();
   int _sumQty = itemsList.fold(0, (a, b) => a + b.quantity!);
   print('$_sumQty was the sum of quantities');
 }
 
 
 Future<List<ItemModel>> loadItems() async {
 
   final List<ItemModel> items = [];
 
   String path = '/items';
   Query resp = FirebaseDatabase.instance.reference().child(path);
 
   FirebaseList(
     query: resp,
     onChildAdded: (i, element) {
       print(element.value);
       ItemModel temp = ItemModel()
         ..item = element.value["item"]
         ..quantity = element.value["quantity"];
       items.add(temp);
     },
     onError: (e) => print(e.message)
   );
 
   await resp.once().then((snapshot) {
     print("${items.length} Items were loaded");
   });
 
   return items;
 }
}

要將其應用於 Firebase 9.1.4,您需要對 loadItems 進行一些更改:

  Future<List<ItemModel>> loadItems() async {

    final List<ItemModel> items = []; 

    String path = '/empresas/-ME9qZY5k8RxpCymZlV2/items';
    Query resp = FirebaseDatabase.instance.ref().child(path);

    FirebaseList(
      query: resp,
      onChildAdded: (i, element) {
        print(element.value);
        Map<dynamic, dynamic> map = element.value as dynamic; 
        ItemModel temp = ItemModel()
          ..item = map["item"]
          ..quantity = map["quantity"];
        items.add(temp);
      },
      onError: (e) => print(e.message)
    );

    await resp.once().then((snapshot) {
      print("${items.length} Items were loaded");
    });

    return items;
  }
}

不要結合awaitthen

代替:

await resp.once().then((snapshot) {
  print("${items.length} Items were loaded");
});

做:

var snapshot = await resp.once();
print("${items.length} Items were loaded");

此類操作不再需要使用onChildAdded 在 Firebase 的 FlutterFire 庫的最新版本中,您可以收聽onValue ,或使用get然后循環您返回的快照的children項。

通過這種簡化,您的代碼可以是:

Future<List<ItemModel>> loadItems() async { 
  Query query = FirebaseDatabase.instance.reference().child('/items');

  var snapshot = await query.once();

  final List<ItemModel> items = snapshot.children.map((element) {
    return ItemModel()
      ..item = element.value["item"]
      ..quantity = element.value["quantity"];
  });

  return items;
}

暫無
暫無

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

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