Flutter Firestore 和 StreamBuilder

Posted

技术标签:

【中文标题】Flutter Firestore 和 StreamBuilder【英文标题】:Flutter Firestore and StreamBuilder 【发布时间】:2020-10-01 14:56:17 【问题描述】:

我正在尝试为我的颤振应用程序构建一个类似于谷歌新闻源的结构。设计部分没有错误。我尝试了一些虚拟数据并且小部件构建正确。当我尝试将 Firestore 数据转换为小部件时,该小部件将不会构建,并且屏幕上没有任何内容。下面是 StreamBuilder 代码

Widget build(BuildContext context) 
    height = MediaQuery.of(context).size.height;
    width = MediaQuery.of(context).size.width;

    return Container(
        color: Colors.green[50],
        height: height,
        width: width,
        child: SingleChildScrollView(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.start,
            children: <Widget>[
              SizedBox(
                height: height * 0.04,
              ),
              Container(
                height: height * 0.12,
                width: width * 0.90,
                color: Colors.green[50],
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.end,
                  children: <Widget>[
                    Align(
                      alignment: Alignment.centerLeft,
                      child: Padding(
                        padding: EdgeInsets.only(left: width * 0.10),
                        child: Text('UPCOMING EVENTS',
                            style: GoogleFonts.tenaliRamakrishna(
                                textStyle: TextStyle(
                                    fontSize: 30,
                                    fontWeight: FontWeight.w500))),
                      ),
                    )
                  ],
                ),
              ),
              StreamBuilder<QuerySnapshot>(
                stream: Firestore.instance.collection('Events').snapshots(),
                builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) 
                  if (snapshot.hasError) 
                    return Center(child: Text('Error: $snapshot.error'),);
                  
                  return ListView(
                    children: snapshot.data.documents
                        .map<Widget>((DocumentSnapshot document) 
                      return eventCard(
                          imageUrl: document['ImageUrl'],
                          title: document['Title'],
                          description: document['Description'],
                          venue: document['Venue'],
                          date: document['Date'],
                          time: document['Time']);
                    ).toList(),
                  );
                ,
              )
            ],
          ),
        ));
  

我的小部件代码是

Widget eventCard(
      String imageUrl,
      String title,
      String description,
      String venue,
      String date,
      String time) 
    return Padding(
      padding: EdgeInsets.all(10),
      child: InkWell(
        onTap: null,
        child: Container(
          height: height * 0.50,
          width: width * 0.90,
          decoration:
              kEventsPage.copyWith(borderRadius: BorderRadius.circular(20)),
          child: Column(
            children: <Widget>[
              Expanded(
                child: ClipRRect(
                  borderRadius: BorderRadius.only(
                      topLeft: Radius.circular(20),
                      topRight: Radius.circular(20)),
                  child: Image.network(
                    imageUrl,
                    width: width * 90,
                    fit: BoxFit.fill,
                    loadingBuilder: (BuildContext context, Widget child,
                        ImageChunkEvent loadingProgress) 
                      if (loadingProgress == null) return child;
                      return Align(
                        alignment: Alignment.bottomRight,
                        child: LinearProgressIndicator(
                          backgroundColor: Colors.grey,
                          value: loadingProgress.expectedTotalBytes != null
                              ? loadingProgress.cumulativeBytesLoaded /
                                  loadingProgress.expectedTotalBytes
                              : null,
                        ),
                      );
                    ,
                  ),
                ),
                flex: 6,
              ),
              Expanded(
                flex: 4,
                child: Padding(
                  padding: EdgeInsets.only(left: 10),
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                    crossAxisAlignment: CrossAxisAlignment.stretch,
                    children: <Widget>[
                      Flexible(
                        child: Text(
                          title,
                          style: GoogleFonts.roboto(
                              textStyle: TextStyle(
                                  fontSize: 20, fontWeight: FontWeight.w500)),
                        ),
                      ),
                      Flexible(
                        child: Text(
                          description,
                          style: GoogleFonts.roboto(
                              textStyle: TextStyle(
                                  fontSize: 15, fontWeight: FontWeight.w400)),
                        ),
                      ),
                      Flexible(
                          child: Row(
                        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                        children: <Widget>[
                          Row(
                            children: <Widget>[
                              Text(
                                'Venue: ',
                                style: GoogleFonts.roboto(
                                    fontWeight: FontWeight.w900),
                              ),
                              Text(venue)
                            ],
                          ),
                          Row(
                            children: <Widget>[
                              Text(
                                'Date: ',
                                style: GoogleFonts.roboto(
                                    fontWeight: FontWeight.w900),
                              ),
                              Text(date)
                            ],
                          ),
                          Row(
                            children: <Widget>[
                              Text(
                                'Time: ',
                                style: GoogleFonts.roboto(
                                    fontWeight: FontWeight.w900),
                              ),
                              Text(time)
                            ],
                          )
                        ],
                      ))
                    ],
                  ),
                ),
              )
            ],
          ),
        ),
      ),
    );
  

错误是

══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter ( 9553): The following NoSuchMethodError was thrown building StreamBuilder<QuerySnapshot>(dirty, state:
I/flutter ( 9553): _StreamBuilderBaseState<QuerySnapshot, AsyncSnapshot<QuerySnapshot>>#21f5c):
I/flutter ( 9553): The getter 'documents' was called on null.
I/flutter ( 9553): Receiver: null
I/flutter ( 9553): Tried calling: documents
I/flutter ( 9553):
I/flutter ( 9553): The relevant error-causing widget was:
I/flutter ( 9553):   StreamBuilder<QuerySnapshot>
I/flutter ( 9553):   file:///D:/Praveen/Flutter/FlutterApps/employee_tracking/lib/screens/Events.dart:169:15
I/flutter ( 9553): 
I/flutter ( 9553): When the exception was thrown, this was the stack:
I/flutter ( 9553): #0      Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)
I/flutter ( 9553): #1      _EventsState.build.<anonymous closure> (package:employeetracking/screens/Events.dart:176:45)
I/flutter ( 9553): #2      StreamBuilder.build (package:flutter/src/widgets/async.dart:509:81)
I/flutter ( 9553): #3      _StreamBuilderBaseState.build (package:flutter/src/widgets/async.dart:127:48)
I/flutter ( 9553): #4      StatefulElement.build (package:flutter/src/widgets/framework.dart:4619:28)
I/flutter ( 9553): #5      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4502:15)
I/flutter ( 9553): #6      StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4675:11)
I/flutter ( 9553): #7      Element.rebuild (package:flutter/src/widgets/framework.dart:4218:5)
I/flutter ( 9553): #8      ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4481:5)
I/flutter ( 9553): #9      StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:4666:11)
I/flutter ( 9553): #10     ComponentElement.mount (package:flutter/src/widgets/framework.dart:4476:5)
I/flutter ( 9553): #11     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3446:14)
I/flutter ( 9553): #12     MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:5947:32)
I/flutter ( 9553): ...     Normal element mounting (111 frames)
I/flutter ( 9553): #123    Element.inflateWidget (package:flutter/src/widgets/framework.dart:3446:14)
I/flutter ( 9553): #124    Element.updateChild (package:flutter/src/widgets/framework.dart:3211:20)
I/flutter ( 9553): #125    ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4527:16)
I/flutter ( 9553): #126    StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4675:11)
I/flutter ( 9553): #127    Element.rebuild (package:flutter/src/widgets/framework.dart:4218:5)
I/flutter ( 9553): #128    BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2627:33)
I/flutter ( 9553): #129    WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:883:20)
I/flutter ( 9553): #130    RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:284:5)
I/flutter ( 9553): #131    SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1113:15)
I/flutter ( 9553): #132    SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1052:9)
I/flutter ( 9553): #133    SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:968:5)
I/flutter ( 9553): #137    _invoke (dart:ui/hooks.dart:261:10)
I/flutter ( 9553): #138    _drawFrame (dart:ui/hooks.dart:219:3)
I/flutter ( 9553): (elided 3 frames from dart:async)
I/flutter ( 9553): 
I/flutter ( 9553): ════════════════════════════════════════════════════════════════════════════════════════════════════
W/libEGL  ( 9553): EGLNativeWindowType 0x78761c2010 disconnect failed
I/SurfaceView( 9553): delay destroy surface control
E/SurfaceView( 9553): surfacePositionLost_uiRtSync  mSurfaceControl = null
W/libEGL  ( 9553): EGLNativeWindowType 0x78760c5010 disconnect failed
I/flutter ( 9553): Another exception was thrown: Vertical viewport was given unbounded height.
I/flutter ( 9553): Another exception was thrown: RenderBox was not laid out: RenderViewport#48731 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
I/flutter ( 9553): Another exception was thrown: RenderBox was not laid out: RenderViewport#48731 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
I/flutter ( 9553): Another exception was thrown: RenderBox was not laid out: RenderIgnorePointer#fd3bc relayoutBoundary=up10 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
I/flutter ( 9553): Another exception was thrown: RenderBox was not laid out: RenderSemanticsAnnotations#0133e relayoutBoundary=up9 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
I/flutter ( 9553): Another exception was thrown: RenderBox was not laid out: RenderPointerListener#5ee9f relayoutBoundary=up8 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
I/flutter ( 9553): Another exception was thrown: RenderBox was not laid out: RenderSemanticsGestureHandler#4cd88 relayoutBoundary=up7 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
I/flutter ( 9553): Another exception was thrown: RenderBox was not laid out: RenderPointerListener#35642 relayoutBoundary=up6 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
I/flutter ( 9553): Another exception was thrown: RenderBox was not laid out: _RenderScrollSemantics#54fe5 relayoutBoundary=up5 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
I/flutter ( 9553): Another exception was thrown: RenderBox was not laid out: RenderRepaintBoundary#15475 relayoutBoundary=up4 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
I/flutter ( 9553): Another exception was thrown: RenderBox was not laid out: RenderCustomPaint#66748 relayoutBoundary=up3 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE  
I/flutter ( 9553): Another exception was thrown: RenderBox was not laid out: RenderRepaintBoundary#01ac9 relayoutBoundary=up2 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
I/flutter ( 9553): Another exception was thrown: RenderBox was not laid out: RenderRepaintBoundary#01ac9 relayoutBoundary=up2 NEEDS-PAINT
I/flutter ( 9553): Another exception was thrown: RenderBox was not laid out: RenderRepaintBoundary#01ac9 relayoutBoundary=up2 NEEDS-PAINT
W/FlutterJNI( 9553): Tried to send a platform message to Flutter, but FlutterJNI was detached from native C++. Could not send. Channel: lyokone/locationstream. Response ID: 0
W/FlutterJNI( 9553): Tried to send a platform message to Flutter, but FlutterJNI was detached from native C++. Could not send. Channel: lyokone/locationstream. Response ID: 0

【问题讨论】:

【参考方案1】:

我找到了原因。这是因为在 Column 小部件中使用了 ListViewColumn 扩展到主轴方向(垂直轴)的最大尺寸,ListView 也是如此

解决方案:

如果您想让ListView 占用Column 中的整个剩余空间,请使用FlexibleExpanded

Column(
  children: <Widget>[
    Expanded(
      child: ListView(...),
    )
  ],
)

【讨论】:

【参考方案2】:

有几件事可以尝试。

1) 替换

if (snapshot.hasError) 
  return Center(child: Text('Error: $snapshot.error'),);
 

与:

if (snapshot.hasError) 
  return Center(child: Text('Error: $snapshot.error'),);

if (!snapshot.hasData) 
  return Center(child: Text('No data'),);

这将使构建器有时间获取数据。

2) 如果您看到 No data,则转到 Firebase 控制台 > 数据库 > firestore 并检查数据库根目录中是否有一个名为 Events 的集合。检查大小写,检查是否有多余的不可见空格。 如果存在,点击查看里面是否有数据

【讨论】:

是的,现在试过了,但屏幕上除了“即将发生的事件”之外什么都没有 数据在那里,如果我在 StreamBuilder 的 builder 方法中打印数据,它会在终端中打印数据。

以上是关于Flutter Firestore 和 StreamBuilder的主要内容,如果未能解决你的问题,请参考以下文章

Flutter Geofire 和 Firestore 读取问题

Firestore 为 noSQL 和 Flutter 复制 SQL 连接

Flutter:Firebase 身份验证和 Firestore 快照流

Flutter 和 Firestore 基于位置的查询和数据结构

使用 Firestore 和 Flutter 填充 DataTable(使用 StreamBuilder)

Flutter multidex 问题与 FirebaseAuth 、 Firestore 和 Google 登录