【发布时间】:2021-11-16 01:41:44
【问题描述】:
我正在尝试使用StreamProvider 进行外汇实时更新。
该演示将通过定期从外部 API 获取最新数据来自动更新汇率。 (本例中每 60 秒一次)
下面是实现图。
图表
API call (Future event) --> Put data in stream
^ |
| V
Wait for 60 seconds <-- StreamProvider listens for
new event and rebuild widget
问题
即使导航到主视图,流也会继续。
如果我们使用StreamBuilder,我们也许可以调用listen()方法,这
将返回StreamSubscription。然后,可以按需调用cancel()、pause() 或resume() 方法。
我想知道在使用StreamProvider时是否有与pause和resume类似的方法?
预期
pause 离开仪表板视图,resume 返回仪表板视图。
代码
型号
class Currency {
String? base;
String? quote;
double? rate;
// constructor, factory constructor, etc.
// ...
}
控制器
class CurrencyService {
Currency? _currency;
Stream<Currency?> get currencyStream async* {
yield* Stream.periodic(Duration(seconds: 60), (_) {
return getCurrencyData();
}).asyncMap((event) async => await event);
}
Future<Currency?> getCurrencyData() async {
try {
// Perform API call and
// update Currency object
// ...
} catch (e) {
print('Error: $e');
}
return _currency;
}
}
查看
void main() async {
runApp(
MultiProvider(
providers: [
// some providers,
// another one,
// ...
StreamProvider<Currency?>(
create: (_) => CurrencyService().currencyStream,
initialData: await CurrencyService().getCurrencyData(),
),
],
child: TestApp(),
),
);
}
class TestApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Live Update Demo',
initialRoute: '/',
routes: routes,
);
}
}
主视图(第 1 页)
class MainView extends StatefulWidget {
const MainView({Key? key}) : super(key: key);
@override
_MainViewState createState() => _MainViewState();
}
class _MainViewState extends State<MainView> {
// ...
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
// ...
ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/dashboard');
},
child: Text('Dashboard')),
],
),
);
}
}
仪表板视图(第 2 页)
class DashboardView extends StatelessWidget {
const DashboardView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(body: Consumer<Currency?>(
builder: (context, currency, child) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
child: Text('${currency?.base ?? ''}${currency?.quote ?? ''}'),
),
Container(
child: Text('${currency?.rate ?? ''}'),
),
],
),
);
},
));
}
}
谢谢。
【问题讨论】:
-
A
Stream.periodic无法暂停和恢复。它将永远运行直到关闭,此时它将永远关闭。相反,使用Timer运行周期性事件并将数据传递到普通的StreamController您的小部件可以收听。 -
@Abion47 感谢您的建议。我已经修改了一些部分,它确实有效。我将在下面的答案部分添加修订。我仍然对使用
StreamProvider的类似实现感到好奇和感兴趣 -
您仍然可以使用
StreamProvider。不要使用默认构造函数,而是使用StreamProvider.value来提供外部流源。 -
@Abion47 我用
StreamProvider.value替换了StreamBuilder,它终于可以工作了!需要一段时间才能弄清楚如何将它与Timer.periodic一起使用。再次感谢!
标签: flutter dart flutter-provider