我正在flutter中实现一个计时器。这是应用程序的结构。
页面A(包含一些列表,用户单击该列表并将其带到计时器页面)。Page B格式可以运行计时器。我能够正确运行计时器/秒表,但是当我按Page BI上的后退按钮时,会在处理错误后调用setstate()。我知道这是预期的行为。如果我在处理时使用timer.cancel(),则不会收到错误消息,但计时器将停止运行。即使我导航至页面A或说其他任何新页面(小部件),计时器/秒表也应继续运行。我知道可以使用侦听器和WidgetBindingObserver来实现,但是我不知道如何实现它。希望我会在此问题上获得一些帮助。
B页的构建类:
Widget build(BuildContext context) { return Scaffold( appBar: AppBar( leading: new IconButton(icon: new Icon(Icons.arrow_back), onPressed: ()async{ Navigator.pop(context,widget._elapsedTime); }), title: Text("widget.title"), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text( '$_elapsedTime'), RaisedButton( child: Text('Start'), onPressed: () { if(watch.isRunning){ stopWatch(); } else{ startWatch(); } }, ), ], ), ));
StartWatch功能:
startWatch() { watch.start(); timer = new Timer.periodic(new Duration(milliseconds:1000), updateTime);}
更新时间函数每秒调用一次:
updateTime(Timer timer) { if (watch.isRunning) { print(_elapsedTime); var time= formatedTime(watch.elapsedMilliseconds); print("time is"+time); setState(() { _elapsedTime = time; }); }
这是一个最小的工作解决方案。关键点:
TimerService
ChangeNotifier
InheritedWidget
AnimatedBuilder
addListener
removeListener
import 'dart:async'; import 'package:flutter/material.dart'; void main() { final timerService = TimerService(); runApp( TimerServiceProvider( // provide timer service to all widgets of your app service: timerService, child: MyApp(), ), ); } class TimerService extends ChangeNotifier { Stopwatch _watch; Timer _timer; Duration get currentDuration => _currentDuration; Duration _currentDuration = Duration.zero; bool get isRunning => _timer != null; TimerService() { _watch = Stopwatch(); } void _onTick(Timer timer) { _currentDuration = _watch.elapsed; // notify all listening widgets notifyListeners(); } void start() { if (_timer != null) return; _timer = Timer.periodic(Duration(seconds: 1), _onTick); _watch.start(); notifyListeners(); } void stop() { _timer?.cancel(); _timer = null; _watch.stop(); _currentDuration = _watch.elapsed; notifyListeners(); } void reset() { stop(); _watch.reset(); _currentDuration = Duration.zero; notifyListeners(); } static TimerService of(BuildContext context) { var provider = context.inheritFromWidgetOfExactType(TimerServiceProvider) as TimerServiceProvider; return provider.service; } } class TimerServiceProvider extends InheritedWidget { const TimerServiceProvider({Key key, this.service, Widget child}) : super(key: key, child: child); final TimerService service; @override bool updateShouldNotify(TimerServiceProvider old) => service != old.service; } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Service Demo', home: MyHomePage(), ); } } class MyHomePage extends StatefulWidget { @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { var timerService = TimerService.of(context); return Scaffold( appBar: AppBar(), body: Center( child: AnimatedBuilder( animation: timerService, // listen to ChangeNotifier builder: (context, child) { // this part is rebuilt whenever notifyListeners() is called return Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text('Elapsed: ${timerService.currentDuration}'), RaisedButton( onPressed: !timerService.isRunning ? timerService.start : timerService.stop, child: Text(!timerService.isRunning ? 'Start' : 'Stop'), ), RaisedButton( onPressed: timerService.reset, child: Text('Reset'), ) ], ); }, ), ), ); } }