Flutter How to make Stream complete before executing the next operation - flutter

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

Related

Semaphore in flutter

Code:
void _test() {
print(1);
Timer.run(() {
print(2);
});
print(3);
}
Print 1 3 2.
I want print 1 2 3.
In iOS I can use Semaphore, how can I do this in flutter?
Awaiting for a method to complete can be written inside a future
void _test() async{
print(1);
Future.delayed(Duration(seconds : 0), (){
print(2);
});
print(3);
}
//Output 1 3 2
void _test() async{
print(1);
await Future.delayed(Duration(seconds : 0), (){
print(2);
});
print(3);
}
//Output 1 2 3
In the second example the await will wait for the future to complete and then move to the next task
Thanks #jamesdlin, I solved with his comment, below is desired code:
void _test() async {
print(1);
Completer<void> completer = Completer();
Timer.run(() {
print(2);
completer.complete();
});
await completer.future;
print(3);
}
Timer.run() basically tells the program that here is a piece of code that should be executed but I don't care if it finishes before it reaches the code outside of this block.
If you want to wait a bit, use Future.delayed:
runAsyncMethod() async {
print("1");
await Future.delayed(Duration(seconds: 3), () {print("2");});
print("3");
}

How can i get time of async function execution?

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);
}

How to use Future Delayed

I have 2 functions. I want to run them one by one but while the first function is done, the second function must wait for 1-2 seconds. I tried Future.delayed for this but it did not work. It changes nothing.
void kartat(int tip, int deger, int mainid, List mycards) {
masadakicards.add(cardbank[mainid]);
print("kart atıldı");
rakipkartat(51);
}
void rakipkartat(int mainid) {
new Future.delayed(Duration(seconds: 1), () {
// deleayed code here
masadakicards.add(cardbank[mainid]);
print("ann");
});
}
A way that you can achieve this is by using await Future.delayed
make sure that your method is returns a Future
Future<void> start() async {
await foo();
await Future.delayed(Duration(seconds: 2));
await bar();
}
Future<void> foo() async {
print('foo started');
await Future.delayed(Duration(seconds: 1));
print('foo executed');
return;
}
Future<void> bar() async {
print('bar started');
await Future.delayed(Duration(seconds: 1));
print('bar executed');
return;
}
expected:
foo started
- waits 1 second -
foo executed
- waits 2 seconds -
bar started
- waits 1 second -
bar executed
Following your methods
Please note that the method that gets executed after the delay also needs to include async and await, otherwise the method will run synchronously and not await the Future.
Future<void> start() async {
foo();
}
void foo() {
Future.delayed(Duration(seconds: 2), () async {
// do something here
await Future.delayed(Duration(seconds: 1));
// do stuff
});
}
Not sure if your overall approach is appropriate (can't tell from this), however,
Future<void> rakipkartat(int mainid) async { should do.
I guess it would be better if you create both and the calling function as Future and then call the functions with await kartet(); await rakipkartat()
By the way, implementing my 1st paragraph also requests that the calling function is a Future or at least handles the call as a Future.

Why does this test using FakeAsync just hang on the "await" even though the future has completed?

I'm trying to write a test using FakeAsync but it seems to hang on my awaits. Here's a stripped down example:
test('danny', () async {
await FakeAsync().run((FakeAsync async) async {
print('1');
final a = Future<bool>.delayed(const Duration(seconds: 5))
.then((_) => print('Delayed future completed!'))
.then((_) => true);
print('2');
async.elapse(const Duration(seconds: 30));
// Tried all this too...
// async.flushMicrotasks();
// async.flushTimers();
// async.elapse(const Duration(seconds: 30));
// async.flushMicrotasks();
// async.flushTimers();
// async.elapseBlocking(const Duration(seconds: 30));
print('3');
await a;
print('4');
expect(1, 2);
});
});
This code outputs:
1
2
Delayed future completed!
3
// hangs and never prints '4'
The async.elapse call is allowing the future to be completed, but it still hangs on await a. Why?
This seems to occur because although the Future is completed, the await call requires the microtask queue to be processed in order to continue (but it can't, since nobody is calling async.elapse after the await).
As a workaround, contiually pumping the microstask queue while the function is running seems to work - for example calling this function in place of FakeAsync.run:
/// Runs a callback using FakeAsync.run while continually pumping the
/// microtask queue. This avoids a deadlock when tests `await` a Future
/// which queues a microtask that will not be processed unless the queue
/// is flushed.
Future<T> runFakeAsync<T>(Future<T> Function(FakeAsync time) f) async {
return FakeAsync().run((FakeAsync time) async {
bool pump = true;
final Future<T> future = f(time).whenComplete(() => pump = false);
while (pump) {
time.flushMicrotasks();
}
return future;
}) as Future<T>;
}
It seems that await does not work inside fakeAsync, so you are stuck with Future.then() and friends.
However you can very easily wait for all Futures to complete by calling time.elapse()and time.flushMicrotasks().
test('Completion', () {
fakeAsync((FakeAsync time) {
final future = Future(() => 42);
time.elapse(Duration.zero);
expect(future, completion(equals(42)));
time.flushMicrotasks();
});
});

How to call async functions in Stream.periodic

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.