0

I was trying to make an app that starts to count when a button is pressed but the app keeps getting stuck, once I press on the button it immediately becomes unresponsive

    class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  void looping() {
    for (int i = 0; i < 100; i++) {
      setState(() {
        counter++;
      });
      sleep(Duration(seconds: 1));
    }
  }

  int counter = 0;
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        backgroundColor: Colors.white,
        floatingActionButton: FloatingActionButton(
          child: Icon(Icons.add),
          onPressed: () {
            looping();
          },
        ),
        body: Center(
          child: Text(counter.toString(),
              style: TextStyle(fontSize: 50.0, fontWeight: FontWeight.bold)),
        ),
      ),
    );
  }
}
  • 1
    Use future instead of sleep for async. refer to this: https://stackoverflow.com/questions/18449846/how-can-i-sleep-a-dart-program – kabayaba Mar 12 '21 at 10:53

3 Answers3

0

This is how sleep works, use it with care, as no asynchronous operations can be processed in a isolate while it is blocked in a sleep call.

To your case consider using Future.delayed or Timer. You can check their usage here What is the difference between Future.delayed vs Timer in flutter

Simon Sot
  • 2,748
  • 2
  • 10
  • 23
0

I see that your call to the sleep function is inside a for loop that counts from 0 to 99, and the sleep function stops the app for 1 second. The problem seems to be that you are not expecting the app to freeze every time you call to the sleep function. But freezing the app it's actually what it is expected to do.

Consider using a Timer.periodic instead. Consider this snippet, which is meant to be part of the state of a stateful widget:

Timer timer;

@override
void initState() {
  super.initState();
  timer = Timer.periodic(Duration(seconds: 1), (Timer t) => print("Test"));
}

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

That code will print "Test" every second, without freezing the app. I think a similar approach is what you need.

In your case, assuming you want your counter to increment one by one every second, and that you want to stop incrementing it after a certain condition is met, you can cancel the timer inside the periodic function to stop it from incrementing. You need something like:

Timer.periodic(const Duration(seconds: 1), (timer) {
  if (counter >= 99) {
    timer.cancel();
  } else {
    setState(() => counter++);
  }
});
drogel
  • 2,567
  • 2
  • 13
  • 22
  • it worked but it increments the value by 100 every second when it should have been 1. –  Mar 12 '21 at 11:23
  • You don't need to run the whole loop inside the periodic callback. Consider the snippet I have added to my edited answer, I think it is what you need for your use case. – drogel Mar 12 '21 at 11:30
0

You could use a Stream.periodic.

class _MyAppState extends State<MyApp> {
  var counter = 0;
  var streamSubscription; // define the subscription varibale

  void looping() {
  final stream = Stream.periodic(Duration(seconds: 1), (int _counter){
   setState(()=>counter = _counter); // increments the counter by 1 every second
   if (_counter == 100){
    streamSubscription.cancel(); // cancels the stream when the counter reaches 100
  }});
  streamSubscription = stream.listen((_) => null); // starts listening to the stream
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        backgroundColor: Colors.white,
        floatingActionButton: FloatingActionButton(
          child: Icon(Icons.add),
          onPressed: () {
            looping();
          },
        ),
        body: Center(
          child: Text(counter.toString(),
              style: TextStyle(fontSize: 50.0, fontWeight: FontWeight.bold)),
        ),
      ),
    );
  }
}
Andrej
  • 2,743
  • 2
  • 11
  • 28