计时器不会取消 - Flutter Provider

Timer doesn't cancel - Flutter Provider

我的应用程序的 objective 是当我点击 start 按钮时,计时器应该启动,每 5 秒 运行 一个功能,当 stopped定时器应该从 运行ning 起取消并停止该功能。 (现在我有不同的屏幕用于相同的目的,所以我制作了一个公共屏幕,现在我将 Timer 计时器发送到那个公共有状态 class 构造函数)。所以,问题是,计时器不会取消,当我点击 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 秒保持一次 运行ning。下面是控制台输出:

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

最终你的问题是你试图在 toggleCompanyTimer 中构造一个 Timer 对象并试图在调用者中分配对该对象的引用。但是,Dart is not pass-by-reference,因此 toggleCompanyTimer 没有直接的方法来做到这一点。

如果您的 StrategyProvider class 完全由自己拥有和管理 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!");
    }
  }
}