I need to do some actions if my http requests lasts more than 1 sec (But not stop it, so i can't use duration property)
How is this possible in Dart?
You can achieve this with a Timer from dart:async:
import 'dart:async';
Future<String> fetchData() async {
await Future.delayed(Duration(seconds: 5));
return 'data';
}
Future<void> main() async {
Timer timer;
timer = Timer(Duration(seconds: 1), () => print("Timer expired!"));
final data = await fetchData();
timer.cancel();
print(data);
}
Related
The f method is a time-consuming operation, and it may be called in several places, and the time is not certain. I hope that the f method can be executed in the order of calling, and then execute the next time.
For example, A and B differ by 1 second to call the f method, and it takes 5 seconds to complete the execution of the f method. I hope that the f will be executed for the second time after 5 seconds.
code:
import 'dart:async';
void main() {
StreamController<int> controller = StreamController();
StreamSubscription streamSubscription =
controller.stream.listen((event) async {
await f(event);
});
controller.add(5);
controller.add(3);
controller.add(1);
}
Future<void> f(int duration) async {
await Future.delayed(Duration(seconds: duration));
print('$duration');
}
output:
1
3
5
the result i want: 5 3 1
How can I modify the code, or what other api to use
Just remove your delay function and use the following:
import 'dart:async';
void main() {
StreamController<int> controller = StreamController();
StreamSubscription streamSubscription =
controller.stream.listen(
(event) => print('Event: $event'),
onDone: () => print('Done'),
onError: (error) => print(error),
);
controller.add(5);
controller.add(3);
controller.add(1);
}
Don't use streams?
Why are you using streams if you want to ruin the point of using them.
void main() async {
await f(5);
await f(3);
await f(1);
}
Future<void> f(int duration) async {
await Future.delayed(Duration(seconds: duration));
print('$duration');
}
output: 5 3 1 with delay 5s, 3s, 1s as you wanted
Is it possible to perform async steps with Timer instead of Future.delayed? The main reason is the availability of cancel() method in the Timer class, which allows me to cancel a running timer when a widget is disposed in Flutter.
import 'dart:async';
const kFirstStepDuration = Duration(seconds: 1);
const kSecondStepDuration = Duration(seconds: 1);
const kThirdStepDuration = Duration(seconds: 1);
void main() async{
await Future.delayed(kFirstStepDuration);
print('first step');
await Future.delayed(kSecondStepDuration);
print('second step');
await Future.delayed(kThirdStepDuration);
print('end');
}
Using the Timer following Richard Heap answer, I would like to cancel the steps whenever its possible, but the code below prompts:
first timer to begin
cancel first
cancel second
cancel third
My expectation was to prompt:
first timer to begin
cancel first
second timer to begin
cancel second
third timer to begin
cancel third
executed in 0:00:00.06000
import 'dart:async';
const kFirstStepDuration = Duration(seconds: 1);
const kSecondStepDuration = Duration(seconds: 1);
const kThirdStepDuration = Duration(seconds: 1);
Timer? firstTimer;
Timer? secondTimer;
Timer? thirdTimer;
final firstCompleter = Completer();
final secondCompleter = Completer();
final thirdCompleter = Completer();
void main() {
threadA();
threadB();
}
void threadA() async {
print('first timer to begin');
firstTimer = Timer(kFirstStepDuration, ()=> firstCompleter.complete());
await firstCompleter.future;
print('second timer to begin');
secondTimer = Timer(kSecondStepDuration, ()=> secondCompleter.complete());
await secondCompleter.future;
print('third timer to begin');
thirdTimer = Timer(kThirdStepDuration, ()=> thirdCompleter.complete());
await thirdCompleter.future;
}
void threadB() async {
await Future.delayed(Duration(milliseconds: 20));
firstTimer?.cancel();
print('cancel first');
await Future.delayed(Duration(milliseconds: 20));
secondTimer?.cancel();
print('cancel second');
await Future.delayed(Duration(milliseconds: 20));
thirdTimer?.cancel();
print('cancel third');
}
await a future that you complete in the timer's callback.
print('starting');
final completer = Completer();
final t = Timer(Duration(seconds: 3), () => completer.complete());
await completer.future;
print('done');
The problem with this is the completer won't complete if the timer is cancelled, as the callback is never called. So you have to cancel the timer and complete the completer.
Wouldn't it be easier to check the widget is still mounted after the Future.delayed?
EDIT
Following the update to your question, it seems you didn't the 'problem' above. You could encapsulate all the functionality into a class like:
class PointlessTimer {
PointlessTimer(Duration d) {
_timer = Timer(d, () => _completer.complete());
}
late final Timer _timer;
final _completer = Completer();
Future get future => _completer.future;
void cancel() {
_timer.cancel();
_completer.complete();
}
}
and use it like this:
void main() async {
print('starting');
final pointless = PointlessTimer(Duration(seconds: 3));
Timer(Duration(seconds: 2), () => pointless.cancel());
await pointless.future;
print('done');
}
Following Richard Heap answer:
/// works as a Future.delayed. Returns a timer to be canceled.
/// useful when disposing widgets before a timer completion.
/// necessary when testing widgets that disposes before the timer completion.
Future<Timer> _delayed(Duration duration) async {
final completer = Completer();
final timer = Timer(duration, () {
completer.complete();
});
await completer.future;
return timer;
}
In C# I can use async and await to process tasks in parallel. I can kick off an asynchronous task, do other things, and finally await for the asynchronous task to complete.
var t = myFunctionAsync();
executeTask1();
executeTask2();
await t;
How can I do this in dart/flutter?
Reference: async-await
void main() async {
var t = myFunctionAsync();
executeTask1();
executeTask2();
await t;
}
Future<int> myFunctionAsync() async {
await Future.delayed(const Duration(seconds: 2));
return 2;
}
void executeTask1() {
// do something
}
void executeTask2() {
// do something
}
void someFunction () async{
executeTask1();
executeTask2();
await executeTask3();
}
I have a function which makes a api call, if i call that api twice, i want to cancel first call i'm trying to use dio for this
import 'package:dio/dio.dart';
final _dio = Dio();
CancelToken abc = CancelToken();
Future<void> makeSearchQuery(String searchTerm) async {
abc.cancel();
return _dio.get(searchTerm, cancelToken: abc).then((value) {
print(value);
}).catchError((e) {});
}
void main() async {
await makeSearchQuery("https://reqres.in/api/products/3");
await makeSearchQuery("https://reqres.in/api/products/3");
}
The problem is i'm not getting any response for either of that, though i should get the response for second call
P.S actually I'm calling this function in onPressed of a button if that matters.
What you need is a debouncer,
class Debouncer {
final int milliseconds;
Timer? _timer;
Debouncer({
this.milliseconds = 500,
});
void run(VoidCallback action) {
if (_timer != null) {
_timer?.cancel();
}
_timer = Timer(Duration(milliseconds: milliseconds), action);
}
}
use run method to call your function.
when timer gets canceled your function won't get called
Is it possible to call an async function inside dart:Stream.periodic function?
I tried to wrap my async function but it is not working, please see code below.
Stream.periodic(Duration(seconds: _pollingInterval), _checkConnectivity)
String _checkConnectivity(int x) async {
return await _connectionRepository.checkConnection();
}
Use asyncMap:
Stream<String> checkConnectionStream() async* {
yield* Stream.periodic(Duration(seconds: _pollingInterval), (_) {
return _connectionRepository.checkConnection();
}).asyncMap((event) async => await event);
}
I'm not too familiar with dart streams yet, but you should be able to simulate what you're trying to achieve like this:
final controller = StreamController<String>();
Timer timer;
controller.onListen = () {
timer = Timer.periodic(
_pollingInterval,
(timer) => _connectionRepository.checkConnection().then((data){
if(!controller.isClosed){
controller.add(data);
}
}),
);
};
controller.onCancel = () {
timer?.cancel();
}
return controller.stream;
The stream does not support pause and continue, though. If you want that you'd need to override the corresponding callbacks on the controller and start/stop the timer there.
Also, depending on the timing of checkConnection this can result in events in the stream being very different to _pollingInterval.