MD. Sajid Hossain
MD. Sajid Hossain

Reputation: 11

How to break a loop after specific duration of time in dart?

I was trying to break the loop after 5 seconds so I used Timer class of dart. But in every loop state timer.tick value is 1. I need help how can I break the loop after 5s or any specific duration of time?

import 'dart:async';

import 'dart:io';

main(List<String> args) {
  String usrName;
  Timer.periodic(Duration(seconds: 1), (timer) {
    while (true) {
      print("What's you're name?");
      usrName = stdin.readLineSync() as String;
      print("Welcome $usrName.");
      //print("${timer.tick}s passed");
      if (timer.tick == 5) {
        print("Ended");
        timer.cancel();
        break;
      }
    }
  });
}

Upvotes: 0

Views: 976

Answers (2)

jamesdlin
jamesdlin

Reputation: 90125

There are many things wrong with your current approach. You've created a Timer that will create a new loop every second, but you instead want a single loop with a Timer that can break out of it. Also, you unfortunately won't be able to use stdin.readLineSync() since that will block execution until the user enters an input line. You will need a completely different approach.

Futures and Streams have a .timeout method that can throw a TimeoutException (or return/emit a specified value). stdin unfortunately doesn't provide a direct way to read lines asynchronously, so you will need to use LineSplitter on it manually.

Another complication is that stdin is a single-subscription stream, which makes reading individual lines a bit awkward. We can use package:async's StreamQueue to make that more intuitive.


import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:async/async.dart';

Future<void> main(List<String> args) async {
  final lines = StreamQueue<String>(utf8.decoder
      .bind(stdin)
      .transform(const LineSplitter())
      .timeout(const Duration(seconds: 5)));

  var questions = [
    'Question 1?',
    'Question 2?',
    'Question 3?',
  ];

  var answers = <String>[];

  for (var question in questions) {
    print(question);

    try {
      answers.add(await lines.next);
    } on TimeoutException {
      break;
    }

    print('');
  }
  lines.cancel();

  print('Got answers: $answers');
}

Upvotes: 0

lrn
lrn

Reputation: 71793

A synchronous loop in Dart does not allow any other events to run, including the timer events which would increment the tick.

Either make your loop asynchronous (by doing await inside it in at least one place, and if you want a timer to run, do it with a Future.delayed(Duartion.zero) to ensure that it allows timer events to run, not just microtask.

Or, what I'd do if I actually want the loop to be synchronous, is to use a Stopwatch:

var sw = Stopwatch()..start();
while (sw.elapsedMilliseconds < 5000) {
  // keep doing
}
// done.

That will stop the loop. It won't time-out the request for input, and it won't allow anything else to run while waiting for input. For those reasons, you might want to use something like what @jamesdlin has suggested.

Upvotes: 1

Related Questions