如何解决Flutter/Firestore/Provider - 瞬间显示错误,然后显示流,如何在启动时加载流值?
我正在使用 Stream Provider 来访问 Firestore 数据并将其传递给我的应用程序。当我第一次运行应用程序时,我面临的问题就开始了。一切都正常开始,但是当我导航到我在列表视图中使用 Stream 值的屏幕时,我最初在 UI 重建之前收到一个错误,并且列表项会在一瞬间出现。这是我得到的错误:
════════ Exception caught by widgets library ═══════════════════════════════════
The following NoSuchMethodError was thrown building OurInboxPage(dirty,dependencies: [_InheritedProviderScope<List<InboxItem>>]):
The getter 'length' was called on null.
Receiver: null
Tried calling: length
我猜这与访问值并将它们添加到屏幕的加载时间有关?如何在应用启动时加载所有流值以避免这种情况?
这是我的流代码:
Stream<List<InboxItem>> get inboxitems {
return orderCollection
.where("sendTo",isEqualTo: FirebaseAuth.instance.currentUser.email)
.snapshots()
.map(
(QuerySnapshot querySnapshot) => querySnapshot.docs
.map(
(document) => InboxItem.fromFirestore(document),)
.toList(),);
}
然后我将其添加到我的提供者列表中:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(
MultiProvider(
providers: [
StreamProvider<List<InboxItem>>.value(value: OurDatabase().inboxitems),],child: MyApp(),),);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Consumer<OurUser>(
builder: (_,user,__) {
return MaterialApp(
title: 'My App',theme: OurTheme().buildTheme(),home: HomepageNavigator(),);
},);
}
}
最后是我想显示流项目的页面:
class OurInboxPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
List<InboxItem> inboxList = Provider.of<List<InboxItem>>(context);
return Scaffold(
body: Center(
child: ListView.builder(
itemCount: inboxList.length,itemBuilder: (context,index) {
final InboxItem document = inboxList[index];
return Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,children: [
Text(document.event),Icon(Icons.arrow_forward_ios)
],);
},);
}
}
谢谢
解决方法
是的,它试图在填充数据之前构建,因此出现空错误。
将您的 ListView.builder
包裹在 StreamBuilder
中,并在没有数据时显示加载指示器。
StreamBuilder<List<InboxItem>>(
stream: // your stream here
builder: (context,snapshot) {
if (snapshot.hasData) {
return // your ListView here
} else {
return CircularProgressIndicator();
}
},);
,
我假设您没有使用最新版本的 provider
,因为最新版本需要 StreamProvider
设置 initialData
。
如果您真的想使用 StreamProvider
而不想使用 null
值,只需设置其 initialData
属性即可。
来自:
StreamProvider<List<InboxItem>>.value(value: OurDatabase().inboxitems),
致:
StreamProvider<List<InboxItem>>.value(
value: OurDatabase().inboxitems,initialData: <InboxItem>[],// <<<<< THIS ONE
),
如果您想在初始执行 getter 函数 inboxitems
时显示一些进度指示器。您无需修改 StreamProvider
,只需在您的 null
小部件中添加一个 OurInboxPage
。
class OurInboxPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final List<InboxItem>? inboxList =
Provider.of<List<InboxItem>?>(context,listen: false);
return Scaffold(
body: inboxList == null
? const CircularProgressIndicator()
: ListView.builder(
itemCount: inboxList.length,itemBuilder: (_,__) => Container(
height: 100,color: Colors.red,),);
}
}
,
有两种方法可以解决这个问题。
-
在加载数据时使用进度条。
StreamBuilder<int>( stream: getStream(),builder: (_,snapshot) { if (snapshot.hasError) { return Text('${snapshot.error}'); } else if (snapshot.hasData) { return Text('${snapshot.data}'); } return Center(child: CircularProgressIndicator()); // <-- Use Progress bar },)
-
最初提供虚拟数据。
StreamBuilder<int>( initialData: 0,// <-- Give dummy data stream: getStream(),snapshot) { if (snapshot.hasError) return Text('${snapshot.error}'); return Text('${snapshot.data}'); },)
这里,getStream()
返回 Stream<int>
。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。