Flutter - 如何在流构建器中使用 await?
Posted
技术标签:
【中文标题】Flutter - 如何在流构建器中使用 await?【英文标题】:Flutter - How do I use await inside the streambuilder? 【发布时间】:2020-08-12 11:58:57 【问题描述】:我想在 streambuilder 中使用 await。但是,如果你在里面使用 async,你会得到一个错误。在下面的代码上!!!!!!!!!这就是我要解决的部分。如果我能告诉你怎么做,非常感谢。
class _MemoStreamState extends State<MemoStream>
final _fireStore = Firestore.instance;
@override
Widget build(BuildContext context)
return StreamBuilder<QuerySnapshot>(
stream: _fireStore
.collection(widget.logInUsrEmail)
.orderBy('id', descending: false)
.snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot)
if (!snapshot.hasData) return LinearProgressIndicator();
final memos = snapshot.data.documents;
List<MemoMaterial> memoList = [];
for (var memo in memos)
final memoDocumentID = memo.documentID;
final memoTitle = await PlatformStringCryptor().decrypt(memo.data['title'], _key); !!!!!!!!!!
final memoUsrID = memo.data['usrID'];
final memoUsrPW = memo.data['usrPW'];
final memoText = memo.data['text'];
final memoCreateTime = memo.data['createTime'];
final memoMaterial = MemoMaterial(
logInUsrEmail: widget.logInUsrEmail,
doc: memoDocumentID,
title: memoTitle,
usrID: memoUsrID,
usrPW: memoUsrPW,
text: memoText,
createTime: memoCreateTime,
);
memoList.add(memoMaterial);
return Expanded(
child: new ListView.builder(
【问题讨论】:
您不能使用异步构建方法。在定义memoTitle
时,您应该编辑您的流并产生结果。有关处理流的帮助,请参阅 the docs。
要编辑流的部分是"stream: _fireStore .collection (widget.logInUsrEmail) .orderBy('id', descending: false) .snapshots()(),"你的意思是?跨度>
【参考方案1】:
你应该这样做:
Stream<List<MemoMaterial>> memosStream;
Future<MemoMaterial> generateMemoMaterial(Memo memo) async
final memoTitle =
await PlatformStringCryptor().decrypt(memo.data['title'], _key);
return MemoMaterial(
logInUsrEmail: widget.logInUsrEmail,
doc: memo.documentID,
title: memoTitle,
usrID: memo.data['usrID'],
usrPW: memo.data['usrPW'],
text: memo.data['text'];,
createTime: memo.data['createTime'],
);
@override
void initState()
memosStream = _fireStore
.collection(widget.logInUsrEmail)
.orderBy('id', descending: false)
.snapshots()
.asyncMap((memos) => Future.wait([for (var memo in memos) generateMemoMaterial(memo)]));
super.initState();
@override
Widget build(BuildContext context)
return StreamBuilder<List<MemoMaterial>>(
stream: memosStream // Use memostream here
asyncMap()
会将每组新文档“转换”为一个 MemoMaterial 列表,并在执行操作时将该列表发送到流中。
Future.wait()
允许同时执行多个异步请求。
【讨论】:
感谢您的良好回复。这很有帮助。但是还有一个问题。即使您使用清单定义 memoStream,它仍然会在列表中显示为 null。有什么问题? 这不应该是.asyncMap((memos) => Future.wait([for (var memo in memos)...
(备忘录而不是文档)吗?
@AugustinR 我在“for (var memo in memos)”语句中收到memos
的错误。错误是“'for' 循环中使用的类型 'QuerySnapshot
我们必须将它从“[for (var memo in memos)”更改为“[for (var memo in memos.docs)”来解决这个问题。谢谢。【参考方案2】:
您可以通过以下方式在 StreamBuilder 中使用 FutureBuilder 来完成。
Stream<List<int>> callme() async*
yield [1, 2, 3, 4, 5, 6];
buildwidget() async
await Future.delayed(Duration(seconds: 1));
return 1;
@override
Widget build(BuildContext context)
return Scaffold(
body: Container(
child: StreamBuilder(
stream: callme(),
builder: (_, sna)
if (sna.hasData)
return FutureBuilder(
future: buildwidget(),
builder: (_, snap)
if (snap.hasData)
return ListView.builder(
itemCount: sna.data.length,
itemBuilder: (_, index)
return Text("$sna.data[index] and $snap.data");
,
);
else
return CircularProgressIndicator();
,
);
else
return CircularProgressIndicator();
),
),
);
【讨论】:
【参考方案3】:如果 UI 依赖于异步函数,我更喜欢使用 Getx 或 Provider 状态管理来处理 UI。
假设您想使用 StreamBuilder()
从 firebase 获取数据,它返回一些包含图像链接的文档,然后您想下载这些图像并从存储中显示。显然,下载图像是异步工作。然后,如果您显示带有直接从StreamBuilder()
获得的链接的图像,则会出现错误。
您可以做的是在getx 或provider 中设置一个变量来显示或隐藏图像Widget。如果图像正在下载或未下载,则将变量设置为在异步类型的函数完成时隐藏/显示图像。
【讨论】:
以上是关于Flutter - 如何在流构建器中使用 await?的主要内容,如果未能解决你的问题,请参考以下文章
Flutter/Firestore - 在流构建器中的动态列表视图上实现“分页”
Flutter StreamBuilder ListView在流数据更改时不会重新加载
Flutter BLoC 模式 - 如何在流事件后导航到另一个屏幕?