Search code examples
flutterdartinitializer

'(callback function) can`t be accessed in an initializer' Error


I am studying flutter while making a pomodoro app. After setting this app to 25 minutes, press the middle button to decrease the time by seconds and press the button again to pause. I am getting the following error while configuring the app using the Timer class. The Timer class takes a repeating period and a callback function as arguments. However, the 'tickDown' function receives the Timer class as an argument, but I don't know why the error pops up. Below is the code I wrote. I'd like to hear your thoughts on what the problem is.

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  var totalSeconds = 1500;
  Timer _timer = Timer.periodic(Duration(seconds: 1), tickDown);
  bool isRunning = false;

  void playTimer() {
    setState(() {
      isRunning = true;
      _timer;
    });
  }

  void pause() {
    _timer.cancel();
    setState(() {
      isRunning = false;
    });
  }

  void tickDown(Timer _timer) {
    setState(() {
      totalSeconds -= 1;
    });
  }

  String showRemainTime() {
    var hour = (totalSeconds ~/ 60).toString();
    var minute = (totalSeconds % 60).toString();
    String time;
    minute.length == 1 ? time = '$hour : 0$minute' : time = '$hour : $minute';
    return time;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Theme.of(context).backgroundColor,
      body: Column(
        children: [
          Flexible(
            flex: 3,
            fit: FlexFit.tight,
            child: Container(
              alignment: const Alignment(0, 0),
              child: Text(
                showRemainTime(),
                textAlign: TextAlign.center,
                style: TextStyle(
                  color: Theme.of(context).cardColor,
                  fontSize: 80,
                  fontWeight: FontWeight.w700,
                ),
              ),
            ),
          ),
          Flexible(
            flex: 4,
            fit: FlexFit.tight,
            child: Container(
              alignment: const Alignment(0, -0.5),
              child: IconButton(
                iconSize: 100,
                padding: EdgeInsets.zero,
                onPressed: isRunning == true ? pause : playTimer,
                icon: Icon(
                  isRunning == true
                      ? Icons.pause_circle_outline_rounded
                      : Icons.play_circle_outlined,
                  color: Theme.of(context).cardColor,
                ),
              ),
            ),
          ),
          Flexible(
            flex: 2,
            fit: FlexFit.tight,
            child: Container(
              decoration: BoxDecoration(
                borderRadius: const BorderRadius.only(
                  topLeft: Radius.circular(30),
                  topRight: Radius.circular(30),
                ),
                color: Theme.of(context).cardColor,
              ),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Text(
                        'Pomodoro',
                        style: TextStyle(
                          fontSize: 23,
                          color: Theme.of(context).textTheme.headline1!.color,
                          fontWeight: FontWeight.w700,
                        ),
                      ),
                      Text(
                        '0',
                        style: TextStyle(
                          fontSize: 52,
                          color: Theme.of(context).textTheme.headline1!.color,
                        ),
                      ),
                    ],
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}

I also searched the flutter official documentation, but I couldn't find anything suitable for my situation. I want to fix this error with minimal modifications to my current code.


Solution

  • tickDown is a method of _HomeScreenState. Object methods cannot be accessed in initializers, because the object has not been fully constructed yet. This includes object properties with assignment definitions (like what you have) as well as initializers specified in constructors.

    There are two ways you can overcome this.

    1. Change your declaration of _timer to be late:
    late var _timer = Timer.periodic(Duration(seconds: 1), tickDown);
    

    However, for your particular situation, I don't recommend this approach.

    1. Instantiate the timer later. This would look like
      Timer? _timer;
    
      void playTimer() {
        setState(() {
          _timer = Timer.periodic(Duration(seconds: 1), tickDown);
          isRunning = true;
        });
      }
    

    Note: To prevent issues, be sure to cancel the timer in the State's dispose() method.