Reputation: 11
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
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.
Future
s and Stream
s 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
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