I am using Streams in Flutter. The problem is that stream.map() is concurrent which means that it doesn't wait one operation to be performed completely. For example:
_sendClientSubject.stream.map((value) async {
await Future.delayed(const Duration(hours: 1));
// do some operation
}).listen((value) {
// do nothing
});
Here, I want the next stream value to wait until I finish my operation. But the case is, instead of waiting for an hour, map is processing each stream value concurrently.
My question is, how can I perform the operation synchronously in Flutter.
Use asyncMap method from rxdart package.
_sendClientSubject.stream.delay(const Duration(hours: 1)).asyncMap((value) {
// do some operation
}).listen((value) {
// do nothing
});
Related
I was going though GSkinner's flutter_vignattes codebase, in one of the functions there was an empty await for a Future
Future<void> _reset() async {
// Wait until next event loop to advance animation and call setState or flutter will yell at you
await Future<void>.value();
_controller.forward(from: 1.0 - _percentage * 0.83);
if (_isLoading) {
setState(() {
_model = BasketballGameModel.randomize();
});
}
_isLoading = false;
}
I understand how promises are sent to micro-task queue in JS (assuming same happens in Dart), but not quite able to understand the reason provided in the comment here i.e.,
// Wait until next event loop to advance animation and call setState or flutter will yell at you
Really appreciate if someone can provide a deeper insight into this. This is the particular line in codebase i am referring to.
https://github.com/gskinnerTeam/flutter_vignettes/blob/0ccc72c5b87b5ab6ba2dee9eff76f48ce2fadec8/vignettes/basketball_ptr/lib/demo.dart#L149
Future<void> function() {}
Defines an asynchronous function that ultimately returns nothing but can notify callers when it eventually completes. Also see: What's the difference between returning void vs returning Future?
Or You can learn from this https://github.com/dart-lang/sdk/issues/33415
I just want to print "After Time" when my local time is greater than my Firebase data document, but it does nothing when my local time is greater only when I restart my application, it shows up print I want it right now displayed
ssaveTimeToFireStrone() async{
await FirebaseFirestore.instance.collection("TimeToChange").doc("Time").set({
"currentTime":atSixInEvening
});
}
Future getTheTime() async{
final DocumentSnapshot doc=await FirebaseFirestore.instance.collection("TimeToChange").doc("Time").get();
DateTime timeToTriggerEvent=doc["currentTime"].toDate();
// await Future.delayed(Duration(seconds: 5));
// print(timeToTriggerEvent);
if(await DateTime.now().isAfter(timeToTriggerEvent)){
print("after time");
return true;
}
}
Thats because the Future is only called once (probably when you start the app).
If you want to continously check if the time is after the trigger time then you have to put it in a loop. I would suggest a timer that checks once every second (so it doesn't cause any performance impact).
How to use the Timer: How to set an Interval in Flutter?
I build a queue of futures to ensure that those futures get completed in a sequential order, because even if one async function is called before the other this won't ensure that they get executed in this order when pushed on the event loop (my assumption).
In the UI there is a button, every time it gets pressed the async computation is pushed onto this queue. When pressed in a way that the async computation is finished before the next button press there isn't a problem but when pressed fast multiple times the computation won't finish.
In the example below every computation after job 1 won't finish.
int i = 0;
class TouchlessAlarmScheduleQueue {
Future _future = Future(() {});
addJob(String alarmId, Future<void> Function() job) {
print('$i added');
int iCopy = i;
_future = _future.then((_) {
print("$iCopy done");
return job();
});
i++;
}
}
Console Output:
flutter: 0 added
flutter: 0 done
flutter: 1 added
flutter: 2 added
flutter: 1 done
[VERBOSE-2:profiler_metrics_ios.mm(203)] Error retrieving thread information: (os/kern) invalid argument
Not sure if this profiler output is related to the problem.
Worked just fine here:
You should probably only use async/await for clarity. I have done the same thing before. I use an improved version in oun production app: https://twitter.com/gazialankus/status/1364695537585381378
I'm newbie to the BLoC design pattern, and I have a question about it:
Does state requires (green) thread-safety?
I give a short psuedocode below:
class Bloc {
State state;
StreamSubscription subscription;
void subscribe(Stream src) {
this.subscription = src.listen(this.businessLogic);
}
async void businessLogic(Object data) {
State oldState = this.state;
State newState = await someAsyncFunction(oldState); // <-- here
this.state = newState;
}
}
In this case, I guess a race condition may happen if two data successively arrive at src:
If the second data arrives while the first data is awaiting someAsyncFunction, the oldState will be the initial state for both of the first and second call of businessLogic.
Is there any good insight about this problem? Thanks!
Dart by default runs on the only 1 thread, so there's no concept of threads in dart. The equivalent term is Isolates and Event Loops which manages Isolates which runs your code on separate thread. So, to answer your question "No", if you don't use Isolates BLOC don't require thread safety.
If you are using Future then It'll also use same Event loop and make your Future function wait till response arrives from the execution of that Future function, so if you want to wait till the response arrives and after that assign another value to newState then you need to use Async await in following fashion.
Future<void> businessLogic(Object data) async{
State oldState = this.state;
State newState = await someAsyncFunction(oldState); // <-- here
this.state = newState;
}
More info on Isolates and Event loops here.
I want to run Future.wait() on some network calls so they can run concurrently. I want to speed this up even further my returning the results as they become available so I can start displaying them. I figured just a small modification to the Future.wait call would be all I need, but unfortunately, it uses private classes internally. Is there a better way to accomplish this?
Future.wait dart documentation
You can use Stream.fromFutures constructor
The stream reports the results of the futures on the stream in the
order in which the futures complete. Each future provides either a
data event or an error event, depending on how the future completes.
If some futures have already completed when Stream.fromFutures is
called, their results will be emitted in some unspecified order.
When all futures have completed, the stream is closed.
Stream<int> streamingInts = Stream.fromFutures([
Future.delayed(Duration(seconds: 1), () => 1),
Future.delayed(Duration(seconds: 2), () => 2),
]);
await for (final i in streamingInts) {
print(i);
}
My real use case - to show that loading takes more time than expected
if my real api call ends fast I just yield LoadedState & stop listen to stream
if my real api call is too slow special Future.delayed will fire special state LoadingTakesTooLongState
Stream<BlocState> loadingStates = Stream.fromFutures([
Future.delayed(_kTooSlowDelay, () => LoadingTakesTooLongState()),
_loadData(),
]);
await for (var state in loadingStates) {
yield state;
if (state is LoadedState) break;
}
Future<LoadedState> _loadData() ...