Таймер не отменяется - провайдер Flutter
Цель моего приложения - когда я нажимаю кнопку, должен запускаться таймер, который запускает функцию каждые 5 секунд, а когда
stopped
таймер должен отменить и остановить выполнение этой функции. (Теперь у меня есть разные экраны для одной и той же цели, поэтому я сделал общий экран и теперь отправляю
Timer
таймер к этому общему конструктору класса с отслеживанием состояния). Итак, проблема в том, что таймер не отменяется, когда я нажимаю
start
функция выполняется каждые 5 секунд, но не останавливается. Ниже я предоставил несколько фрагментов кода, относящихся к моему запросу.
Главный экран:
class StrategyOneScreen extends StatefulWidget {
const StrategyOneScreen({Key? key}) : super(key: key);
@override
State<StrategyOneScreen> createState() => _StrategyOneScreenState();
}
class _StrategyOneScreenState extends State<StrategyOneScreen> {
@override
Widget build(BuildContext context) {
Timer timer1 = Timer(Duration(), () {});
return StrategyScreen(
stratName: 'Free Strategy',
timer: timer1,
toggle: Provider.of<StrategyProvider>(
context,
listen: true,
).companyStratOneToggle,
toggleTimer: Provider.of<StrategyProvider>(
context,
listen: false,
).toggleCompanyTimer,
setToggle: Provider.of<StrategyProvider>(
context,
listen: false,
).setCompanyStratOneToggle,
chartLiveData: Provider.of<StrategyProvider>(
context,
listen: true,
).companyChartLiveData,
);
}
}
Внутри общего
StrategyScreen
:
class StrategyScreen extends StatefulWidget {
const StrategyScreen({
Key? key,
required this.stratName,
required this.timer,
required this.toggle,
required this.toggleTimer,
required this.setToggle,
required this.chartLiveData,
}) : super(key: key);
final stratName;
final timer;
final toggle;
final toggleTimer;
final setToggle;
final chartLiveData;
@override
_StrategyScreenState createState() => _StrategyScreenState();
}
class _StrategyScreenState extends State<StrategyScreen> {
@override
Widget build(BuildContext context) {
print("Timer: ${widget.timer}"); // console logs:=> Timer: null
return Scaffold(
...
Row(
children: [
Expanded(
child: Center(
child: FloatingActionButton.extended(
heroTag: 'btn1',
onPressed: widget.toggle == false
? () => {
widget.toggleTimer(
ref,
showNotification('title', 'body'),
widget.timer,
widget.toggle,
),
widget.setToggle(),
}
: null,
label: Text('Start'),
icon: Icon(Icons.launch),
backgroundColor: Colors.greenAccent,
),
),
),
Expanded(
child: Center(
child: FloatingActionButton.extended(
heroTag: 'btn2',
onPressed: widget.toggle
? () => {
widget.toggleTimer(
ref,
showNotification('title', 'body'),
widget.timer,
widget.toggle,
),
widget.setToggle(),
}
: null,
label: Text('Stop'),
icon: Icon(Icons.stop),
backgroundColor: Colors.pink,
),
),
),
],
),
StrategyProvider.dart
:
class StrategyProvider with ChangeNotifier {
// Toggles
bool _companyStratOneToggle = false;
bool get companyStratOneToggle => _companyStratOneToggle;
ChartLiveData _companyChartLiveData = ChartLiveData(
...
);
ChartLiveData get companyChartLiveData => _companyChartLiveData;
toggleCompanyTimer(ref, showNotification, timer, bool toggle) {
if (toggle == false) {
timer = Timer.periodic(
Duration(seconds: 5),
(Timer t) => {
fetchCompanyLiveStockData( // The function I want to run every 5 seconds
ref,
showNotification,
),
},
);
} else {
timer.cancel();
print("Timer Canceled!");
}
}
// Toggle setters for different strategies
setCompanyStratOneToggle() {
_companyStratOneToggle = !_companyStratOneToggle;
notifyListeners();
}
}
Как я уже говорил ранее, я могу запустить таймер, но не могу его отменить (так как он
null
) и продолжает работать каждые 5 секунд. Ниже представлен вывод консоли:
Unhandled Exception: NoSuchMethodError: Class 'Future<dynamic>' has no instance method 'call'.
E/flutter ( 2746): Receiver: Instance of 'Future<dynamic>'
E/flutter ( 2746): <asynchronous suspension>
E/flutter ( 2746):
I/flutter ( 2746): Timer: null
И когда я нажимаю
cancel
кнопка:
The following NoSuchMethodError was thrown while handling a gesture:
The method 'cancel' was called on null.
Receiver: null
Tried calling: cancel()
When the exception was thrown, this was the stack
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:63:5)
#1 StrategyProvider.toggleSbinTimer
package:myapp/…/global/strategy_provider.dart:67
#2 _StrategyScreenState.build.<anonymous closure>
package:myapp/…/global/strategy_screen.dart:152
1 ответ
В конечном итоге ваша проблема в том, что вы пытаетесь создать объект и пытаетесь назначить ссылку на этот объект в вызывающей стороне. Однако Dart не передается по ссылке , поэтому прямого пути для
toggleCompanyTimer
сделать это.
Вам было бы намного лучше, если бы ваш
StrategyProvider
класс владел и управлял
Timer
объект полностью сам по себе. Например:
class StrategyProvider with ChangeNotifier {
Timer? timer;
// ... Other code...
void toggleCompanyTimer(ref, showNotification, bool stopTimer) {
// Cancel any existing Timer before creating a new one.
timer?.cancel();
timer = null;
if (!stopTimer) {
timer = Timer.periodic(
Duration(seconds: 5),
(Timer t) => {
fetchCompanyLiveStockData(
ref,
showNotification,
),
},
);
} else {
print("Timer Canceled!");
}
}
}