[英]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;
}
}
不要結合await
和then
。
代替:
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.