如何在flutter Streambuilder中重新启动流



我有一个简单的流,它在执行操作时返回倒计时。

static Stream<double> counterStream = (() async* {
double i = 0.1;
double z = 0.0;
while (z < 0.99) {
await Future.delayed(Duration(seconds: 1));
yield  z = z+i;
}
})();

当小部件初始化时,我不会立即启动它,而是通过录制StreamBuilder 内部的按钮

onPressed: () {
setState(() {
_result = DatabaseAccess.counterStream;
});},

第一次Stream正确运行,但第二次没有启动,如果我关闭屏幕并再次返回,请启动流-我得到一个错误

错误状态:流已被侦听。

我不知道如何通过单击按钮来重新加载已经完成执行并且理论上状态为ConnectionState.done的流。

全类代码

class UpdatePage extends StatefulWidget {
UpdatePage({Key key, this.title}) : super(key: key);
static const String routeName = "/UpdatePage";
final String title;
@override
_UpdatePageState createState() => new _UpdatePageState();
}

class _UpdatePageState extends State<UpdatePage> {
Stream<double> _result;
@override
Widget build(BuildContext context) {

return new Scaffold(
appBar: new AppBar(
title: new Text(""),
),
body: SafeArea(
child: StreamBuilder<double>(
stream:  _result,
builder: (BuildContext context, AsyncSnapshot<double> snapshot) {
List<Widget> children;
if (snapshot.hasError) {
children = <Widget>[
Center(
child: Icon(
Icons.error_outline,
color: Colors.red,
size: 60,
),
),
Padding(
padding: const EdgeInsets.only(top: 16),
child: Text('Error: ${snapshot.error}'),
)
];
} else {
switch (snapshot.connectionState) {
case ConnectionState.none:
children = <Widget>[
Center(child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(child: Text("Обновление данных", style: new TextStyle( fontSize: 18.0))),
)),
Center(
child: Container(padding: EdgeInsets.all(20.0),child: RaisedButton.icon(
textColor: Colors.white,
icon:   FaIcon(FontAwesomeIcons.retweet, size: 18,),
color: Color(0xFF6200EE), label: Text("Обновить"),
onPressed: () {
setState(() {
_result = DatabaseAccess.counterStream;
});
},
),),
),
];
break;
case ConnectionState.waiting:
children = <Widget>[
Center(
child: new Padding(
padding: EdgeInsets.symmetric(horizontal: 10.0),
),
),
new CircularPercentIndicator(
radius: MediaQuery.of(context).size.width/2,
lineWidth: 4.0,
center: new Text('', style: new TextStyle( fontSize: 20.0)),
),
];
break;
case ConnectionState.active:
children = <Widget>[
Center(
child: new Padding(
padding: EdgeInsets.symmetric(horizontal: 10.0),
),
),
new CircularPercentIndicator(
radius: MediaQuery.of(context).size.width/2,
lineWidth: 4.0,
percent: snapshot.data,
center: new Text('${snapshot.data.toStringAsFixed(2)}', style: new TextStyle( fontSize: 20.0)),
progressColor: Colors.orange,
),
];
break;
case ConnectionState.done:
children = <Widget>[
new CircularPercentIndicator(
radius: MediaQuery.of(context).size.width/2,
lineWidth: 4.0,
center: new Icon(
Icons.done,
size: MediaQuery.of(context).size.width/4,
color: Colors.green,
),
backgroundColor: Colors.grey,
progressColor: Colors.orange,
)
,
Center(child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(child: Text("Обновление успешно завершено", style: new TextStyle( fontSize: 18.0))),
)),
Center(
child: Container(padding: EdgeInsets.all(20.0),child: RaisedButton.icon(
textColor: Colors.white,
icon:   FaIcon(FontAwesomeIcons.retweet, size: 18,),
color: Color(0xFF6200EE), label: Text("Обновить"),
onPressed: () {
setState(() {
_result = DatabaseAccess.counterStream;
});
},
),),
),
];
break;
}
}
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: children,
);
},
)
));
;

}

}

由于counterStream是静态的,因此它在应用程序的生命周期内初始化一次。在初始化期间,async*函数被调用一次。

因此,在应用程序的生命周期中只创建一个流。CCD_ 4是对该流的引用。

第二次按下按钮时,您将_result设置为原来的值,即我上面提到的流的引用。因此,StreamBuilder不会更改任何内容。就它而言,这是一次没有改变的重建。

当您关闭屏幕并返回时,新的StreamBuilder正试图将现有的、已侦听的流视为新流,因此出现错误。

解决方案

我想你是在试图每次按下按钮都重新开始倒计时。将代码编辑为这样可能会解决问题:

static Stream<double> Function() counterStream = () async* {
double i = 0.1;
double z = 0.0;
while (z < 0.99) {
await Future.delayed(Duration(seconds: 1));
yield  z = z+i;
}
};
onPressed: () {
setState(() {
_result = DatabaseAccess.counterStream();
});},

最新更新