StreamBuilder快照为空,持续几秒钟

时间:2019-04-28 12:35:07

标签: dart flutter rxdart

我正在尝试将RxDart与BLoC模式结合使用,我想通过StreamBuilder从列表中获取事件。

我的问题是,当我打开详细信息屏幕时,大约1秒钟,我收到以下错误消息:The method 'firstWhere' was called on null.

是否有一种方法可以等待获取数据而不添加加载进度,因为我想将HeroAnimation保留在图像上?

class _EventsDetailsScreenState extends State<EventsDetailsScreen> {
  @override
  Widget build(BuildContext context) {
    final eventBloc = BlocProvider.of<EventsBloc>(context);
    //Event event = eventBloc.events.firstWhere((elmt) => elmt.id == widget.id, orElse:() => null);
    return StreamBuilder(
      stream : eventBloc.allEvents,
      builder: (context, snapshot){
        final Event event = snapshot.data.firstWhere((elmt) => elmt.id == widget.id, orElse:() => null);
        return Scaffold(
          body: Stack(
            children: <Widget>[
              Column(children: <Widget>[
                Expanded(
                    child: ListView(
                  shrinkWrap: true,
                  children: <Widget>[
                    _buildEventImage(context, event),
                    (event.description != null && event.description.trim().isNotEmpty) ? _buildDescriptionSection(context, event) : Container(),
                  ],
                ))
              ]),
              new Positioned(
                //Place it at the top, and not use the entire screen
                top: 0.0,
                left: 0.0,
                right: 0.0,
                child: AppBar(
                  actions: <Widget>[
                    IconButton(icon: Icon(Icons.create), onPressed: () async => print('Edit')),
                  ],
                  backgroundColor: Colors.transparent, //No more green
                  elevation: 0.0, //Shadow gone
                ),
              ),
            ],
          ),
        );
      },
    );
  }

  Widget _buildEventImage(BuildContext context, Event event) {
    return Hero(
      tag: 'eventImg${event.id}',
      child: Container(
          decoration: BoxDecoration(
            image: DecorationImage(
                image: AssetImage("images/croatia.jpg"),
                alignment: Alignment.topCenter,
                fit: BoxFit.fill),
          ),
          padding: EdgeInsets.only(left: 40.0, bottom: 250.0),
          alignment: Alignment.bottomLeft,
          height: MediaQuery.of(context).size.height - 30.0,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.end,
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              Container(
                child: Material(
                    color: Colors.transparent,
                    child: Text(
                      event.name,
                      style: eventNameTextStyle,
                    )),
              ),
              Container(
                  child: Material(
                      color: Colors.transparent,
                      child: Text(
                          "In ${event.date.difference(DateTime.now()).inDays} days",
                          style: eventDateTextStyle)))
            ],
          )),
    );
  }

2 个答案:

答案 0 :(得分:0)

您可以添加if语句来检查快照中是否有数据,这样firstWhere函数将仅在快照中有数据时被调用:

 class _EventsDetailsScreenState extends State<EventsDetailsScreen> {
 @override
 Widget build(BuildContext context) {
  final eventBloc = BlocProvider.of<EventsBloc>(context);
  //Event event = eventBloc.events.firstWhere((elmt) => elmt.id == widget.id, orElse:() => null);
  return StreamBuilder(
  stream : eventBloc.allEvents,
  builder: (context, snapshot){
   if(snapshot.hasData){
     return Scaffold(
      body: Stack(
        children: <Widget>[
          Column(children: <Widget>[
            Expanded(
                child: ListView(
              shrinkWrap: true,
              children: <Widget>[
                _buildEventImage(context, event),
                (event.description != null && event.description.trim().isNotEmpty) ? _buildDescriptionSection(context, event) : Container(),
              ],
            ))
          ]),
          new Positioned(
            //Place it at the top, and not use the entire screen
            top: 0.0,
            left: 0.0,
            right: 0.0,
            child: AppBar(
              actions: <Widget>[
                IconButton(icon: Icon(Icons.create), onPressed: () async => print('Edit')),
              ],
              backgroundColor: Colors.transparent, //No more green
              elevation: 0.0, //Shadow gone
            ),
          ),
        ],
      ),
    );
  }else{
    return Scaffold();
  }
});
}

答案 1 :(得分:0)

希望您已经解决了这个问题, 但是在Flutter中使用BLoC模式时,我遇到了同样的问题。 问题来自以下事实:流是异步,而构建方法是同步

  • 这是来自官方文档

可以通过指定initialData来控制初始快照数据。 这应该用于确保第一帧具有预期的 值,因为构建器将始终在流侦听器之前调用 有机会得到处理。 StreamBuilder class

因此,为了避免这种行为,您必须在StreamBuilder中使用initialData属性

要将其与BLoC一起使用,您可以在BLoC处暴露一个简单的 getter ,该 getter 可以获取当前状态同步作为任何新订户的初始数据。