Отменить флаттер-таймер

Я хочу остановить таймер при переходе на другую страницу. Ниже приведен мой код


//imports
late Timer timer;

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  var selectedIndex = 0;

  @override
  Widget build(BuildContext context) {
    Widget page;
    switch (selectedIndex) {
      case 0:
        page = const MonitorPage();
      case 1:
        page = const ReportPage();
      case 2:
        page = const Placeholder();
      default:
        throw UnimplementedError("not found");
    }
    return LayoutBuilder(builder: (context, constraints) {
      return Scaffold(
        body: Row(
          children: [
            SafeArea(
              child: NavigationRail(
                extended: constraints.maxWidth >= 600,
                destinations: const [
                  NavigationRailDestination(
                    icon: Icon(Icons.home),
                    label: Text('main'),
                  ),
                  NavigationRailDestination(
                    icon: Icon(Icons.list),
                    label: Text('report'),
                  ),
                  NavigationRailDestination(
                    icon: Icon(Icons.settings),
                    label: Text("setting"),
                  ),
                ],
                selectedIndex: selectedIndex,
                onDestinationSelected: (value) {
                  setState(() {
                    if (selectedIndex == 0) {
                      timer.cancel(); // here I'd like to cancel the timer
                    }
                    selectedIndex = value;
                  });
                },
              ),
            ),
            Expanded(
              child: Container(
                color: Theme.of(context).colorScheme.primaryContainer,
                child: page,
              ),
            )
          ],
        ),
      );
    });
  }
}


class _MonitorPageState extends State<MonitorPage> {
  late String _time;

  @override
  void initState() {
    _time =
        "${DateTime.now().year.toString().padLeft(4, '0')}-${DateTime.now().month.toString().padLeft(2, '0')}-${DateTime.now().day.toString().padLeft(2, '0')} ${DateTime.now().hour.toString().padLeft(2, '0')}:${DateTime.now().minute.toString().padLeft(2, '0')}:${DateTime.now().second.toString().padLeft(2, '0')}";
    timer = Timer.periodic(const Duration(seconds: 1), (timer) { // here i set the timer variable
      _updateTime(); //just updating time
    });
    super.initState();
  }
  @override
  Widget build(BuildContext context) {
    ...
}
}

Я ожидал отменить таймер, но он выдал мне такое сообщение.


======== Exception caught by gesture ===============================================================
The following LateError was thrown while handling a gesture:
LateInitializationError: Field 'timer' has not been initialized.

When the exception was thrown, this was the stack: 
#0      timer (package:TPSEM_pocket/main.dart)
#1      _MyHomePageState.build.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:TPSEM_pocket/main.dart:184:23)
#2      State.setState (package:flutter/src/widgets/framework.dart:1203:30)
#3      _MyHomePageState.build.<anonymous closure>.<anonymous closure> (package:TPSEM_pocket/main.dart:182:19)
#4      _NavigationRailState.build.<anonymous closure> (package:flutter/src/material/navigation_rail.dart:463:62)
#5      _InkResponseState.handleTap (package:flutter/src/material/ink_well.dart:1183:21)
#6      GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:315:24)
#7      TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:652:11)
#8      BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:309:5)
#9      BaseTapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:242:7)
#10     PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:670:9)
#11     PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:98:12)
#12     PointerRouter._dispatchEventToRoutes.<anonymous closure> (package:flutter/src/gestures/pointer_router.dart:143:9)
#13     _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:633:13)
#14     PointerRouter._dispatchEventToRoutes (package:flutter/src/gestures/pointer_router.dart:141:18)
#15     PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:127:7)
#16     GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:495:19)
#17     GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:475:22)
#18     RendererBinding.dispatchEvent (package:flutter/src/rendering/binding.dart:430:11)
#19     GestureBinding._handlePointerEventImmediately (package:flutter/src/gestures/binding.dart:420:7)
#20     GestureBinding.handlePointerEvent (package:flutter/src/gestures/binding.dart:383:5)
#21     GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:330:7)
#22     GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:299:9)
#23     _invoke1 (dart:ui/hooks.dart:328:13)
#24     PlatformDispatcher._dispatchPointerDataPacket (dart:ui/platform_dispatcher.dart:429:7)
#25     _dispatchPointerDataPacket (dart:ui/hooks.dart:262:31)
Handler: "onTap"
Recognizer: TapGestureRecognizer#0c5e3
  debugOwner: GestureDetector
  state: possible
  won arena
  finalPosition: Offset(115.5, 71.5)
  finalLocalPosition: Offset(115.5, 19.5)
  button: 1
  sent tap down
====================================================================================================

в этом вся суть => LateInitializationError: Field 'timer' has not been initialized.

Я попытался использовать переменную состояния и установить для нее значение таймера, а затем отменить ее в onDestinationSelected (прямо перед изменением переменной selectedIndex), но это тоже не сработало. Как я могу это исправить? Спасибо.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
74
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Определите переменную timer внутри класса _MyHomePageState. Это будет доступно в рамках государственного класса и может быть отменено.
Кроме того, отмените timer в методе dispose(), чтобы избежать утечек памяти, и он остановит или отменит timer.

Вот обновленный код:

class _MyHomePageState extends State<MyHomePage> {
  late Timer timer; // Define timer variable here

  // Rest of your code...

  // This will call when the state object is initiate
  @override
  void initState() {
    super.initState();
    // Initialize the timer here
    timer = Timer.periodic(const Duration(seconds: 1), (timer) {
      _updateTime(); //just updating time
    });
  }

  // This will call when the state object is removed
  @override
  void dispose() {
    // Cancel the timer when the state is disposed
    timer.cancel();
    super.dispose();
  }

  // Rest of your code...
}

В этом случае вы можете разместить свою переменную таймера в методе удаления следующим образом.

  @override
  void dispose() {
    timer.cancel();
    super.dispose();
  }

Попробуйте приведенный ниже код для доступа к таймеру, передайте ссылочный объект на страницу монитора и используйте подход управления состоянием для доступа к таймеру на всех страницах.

import 'package:flutter/material.dart';
import 'dart:async';

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  
  Timer? timer;
  int selectedIndex = 0;

  @override
  Widget build(BuildContext context) {
    Widget page;
    switch (selectedIndex) {
      case 0:
        page = MonitorPage(timer);
      case 1:
        page = const ReportPage();
      case 2:
        page = const Placeholder();
      default:
        throw UnimplementedError("not found");
    }
    return LayoutBuilder(builder: (context, constraints) {
      return Scaffold(
        body: Row(
          children: [
            SafeArea(
              child: NavigationRail(
                extended: constraints.maxWidth >= 600,
                destinations: const [
                  NavigationRailDestination(
                    icon: Icon(Icons.home),
                    label: Text('main'),
                  ),
                  NavigationRailDestination(
                    icon: Icon(Icons.list),
                    label: Text('report'),
                  ),
                  NavigationRailDestination(
                    icon: Icon(Icons.settings),
                    label: Text("setting"),
                  ),
                ],
                selectedIndex: selectedIndex,
                onDestinationSelected: (value) {
                  setState(() {
                    if (selectedIndex == 0) {
                      timer?.cancel(); // here I'd like to cancel the timer
                    }
                    selectedIndex = value;
                  });
                },
              ),
            ),
            Expanded(
              child: Container(
                color: Theme.of(context).colorScheme.primaryContainer,
                child: page,
              ),
            )
          ],
        ),
      );
    });
  }
}

class MonitorPage extends StatefulWidget {
  Timer? timer;
  MonitorPage(this.timer,{super.key});

  @override
  State<MonitorPage> createState() => _MonitorPageState();
}

class _MonitorPageState extends State<MonitorPage> {
  late String _time;
 

  @override
  void initState() {
    _time =
        "${DateTime.now().year.toString().padLeft(4, '0')}-${DateTime.now().month.toString().padLeft(2, '0')}-${DateTime.now().day.toString().padLeft(2, '0')} ${DateTime.now().hour.toString().padLeft(2, '0')}:${DateTime.now().minute.toString().padLeft(2, '0')}:${DateTime.now().second.toString().padLeft(2, '0')}";
    widget.timer = Timer.periodic(const Duration(seconds: 1), (timer) { // here i set the timer variable
      _updateTime(); //just updating time
    });
    super.initState();
  }
  @override
  Widget build(BuildContext context) {
    ...
  }
}

Другие вопросы по теме