我正在尝试将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)))
],
)),
);
}
答案 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 可以获取当前状态的同步值作为任何新订户的初始数据。