A workaround to using an async operation inside setState - flutter

I have an async operation, the result of which should rebuild a widget.
The setState() doc says that
The provided callback is immediately called synchronously. It must not
return a future (the callback cannot be async), since then it would be
unclear when the state was actually being set
So I had a simple workaround which meets my purpose but I am not sure if this is the right approach.
// awaiting for an async operation
distanceFromCenter = await Geolocator().distanceBetween(
selectedLocation.latitude,
selectedLocation.longitude,
ReferencePoint.latitude,
ReferencePoint.longitude);
setState(() {
// A colleague might not know why we're calling the setState() here
});
Any suggestions are welcome.

Related

What is the purpose of awaiting the empty Future in this animation code?

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

misleading concept of future and async programming in flutter

I found it a bit confused with the concept of Future and async programming.
By definition, Future is a type that async function will return in Future.
The purpose is that we want the program to keep running while it is still waiting for the result of the async function.
What I dont understand is that, every often/always, I saw people using async with await which stop proceeding the program until it gets the result from async function called.
Arent we come to full circle? At first, async comes in for the situation that we dont want to wait for program taking time. But now, we use async with await in which we wait until the result is there
It is not always necessary to use await with a future. await can be used if you want to do further processing with the data.
Example:
Future<int> _getInt()async{
Future.delay(Duration(seconds:3)); //simulating network delay
return 7;
}
void _add() async{
int res = await _getInt() + 10; //need to await because we are going to use a future variable
_putInt(res); //not nesscary to await if you don't want to handle the response
/* Ex: var result = await _putInt(); // if you want to handel the response
if (result.statusCode==200){
// handle success
}else{
// handle error
}*/
}
Future _putInt(int number)async{
var res = await http.post('url',body:{'data':number});
return res;
}
Well, your institution is right, we use Future and async as it is nonblocking and follows an event loop approach, meaning there is a callback to the Future when it is ready to execute.
Coming to your point, I have done this myself a lot of time. And neither approach is wrong.
But when it comes to Flutter, it is in your best interest that you don't do anything else when running an async function because dart is single-threaded.
This can be blocking sometimes depending on the work of the function.
This can also be simply for UX as some data would be critical to your application and you shouldn't allow the user to do anything else until it is loaded.

Future<void> async vs simply void async in Dart

In Dart,
what is the difference between saying
Future<void> doStuff() async { ...
and
void doStuff() async { ...
I know what a Future<T> is and how async/await work generally, but I never realized Future<void> was a thing. I have some code that has the Future<void> all over the place and I want to replace it with my normal way of doing things, but I don't want to break anything.
Notice that both functions use async. The question is NOT 'what is the difference between async and non-async functions?' or 'can you give a brief attempt at explaining asynchronous programming in Dart, please?'
I'm aware that there is a pretty much identical question already, but if you look closely at the answers you will see nobody actually answered the question in a clear way -- what is the difference? Is there any difference? Is there no difference?
To elaborate, consider the following two functions:
// notice there is no warning about not returning anything
Future<void> futureVoid() async {
await Future.delayed(Duration(seconds: 2), () {
var time = DateTime.now().toString();
print('$time : delay elapsed');
});
}
void nonFutureVoid() async {
await Future.delayed(Duration(seconds: 2), () {
var time = DateTime.now().toString();
print('$time : delay elapsed');
});
}
Then test them with a button whose onPressed() function is:
onPressed: () async {
await nonFutureVoid(); // notce that this await *DOES* delay execution of the proceeding lines.
var time = DateTime.now().toString();
print('$time : <-- executed after await statement');
}
Log result:
flutter: 2021-02-23 21:46:07.436496 : delay elapsed
flutter: 2021-02-23 21:46:07.437278 : <-- executed after await statement
As you can see, they both behave exactly the same way -- the simple void async version IS awaited. So what is the difference?
With your edit, your question makes more sense. Your question is really about principle vs. practice.
In principle, a function that returns void is different from a function that returns Future<void>. One conceptually represents something that does not return anything, and the other represents an asynchronous computation that can fire callbacks when it completes.
In principle, you should never attempt to use the value returned from a void function. It doesn't make sense. If you run the Dart analyzer against code that does await nonFutureVoid(); you'll get a warning if the await_only_futures lint is enabled.
In practice, there are cases where attempting to use a void return value happens to not generate an error. Those are quirks in the language (or bugs in the implementation); you should not rely on them. (Dart didn't originally have a void return type. When it was added later, it wasn't implemented to mean "no value" but instead to mean "a value that you aren't allowed to use". See Dart 2: Legacy of the void. Normally that subtle difference shouldn't matter.)
Being able to do await nonFutureVoid(); is a bug1, and it seems that that bug is now fixed: await nonFutureVoid(); is an error if you use Dart 2.12 or later and enable null-safety and the stricter type-checking that comes with it.
You can observe the old and new behaviors with DartPad by toggling the "Null Safety" button: https://dartpad.dartlang.org/b0dae0d5a50e302d26d93f2db3fa6207
1 There are a lot of issues filed on GitHub with a lot of back-and-forth discussion, so yes, it is rather confusing. Most people seemed to agree that allowing await void was undesirable, however.
A void function indicates that the function returns nothing, which means you can not act on the result of that Function (and cannot await on it's result).
Meanwhile, the Future<void> function returns a Future object (that has value of void). If you don't have a return statement, a missing_return warning will show up (it can still be compiled). You can still act on that result by awaiting it, but cannot actually use the value because it's void.
While it seems like it'd be just fine with whatever you are using, I think it's better to use Future for every async function for type-safety and better maintenance.

Flutter: what can I put in setState() method?

is there a meaningful difference between these?
setState(() {
_registerIndex++;
});
_registerScrollController.jumpTo(0);
and
setState(() {
_registerIndex++;
_registerScrollController.jumpTo(0);
});
There is no difference, as long as none of them awaits for a Future.
However, if you don't need to update the counter value in your UI, you also don't need setState in this case, because ScrollController.jumpTo() will do the job internally.

What is the point of adding a callback to setState and not just calling setState without one? [duplicate]

This question already has answers here:
Why does setState take a closure?
(2 answers)
Closed 4 years ago.
I am still a bit confused by the difference between these two
isBusy = false;
setState(() {
});
and
setState(() {
isBusy = true;
});
What is the difference between the two? I have read the API but unfortunately, I am still not clear on what difference does it make. I know setState calls the build method of the widget. The API states
Whenever you change the internal state of a State object, make the
change in a function that you pass to setState: setState(() { _myState
= newValue }); The provided callback is immediately called synchronously.
What exactly does this mean? can anyone give me a super simple example of when this would make a difference?
There's no difference between using setState callback or not actually.
What's the point then ?
This is made voluntarily to prevent mistakes in handling asynchronous data.
By using the callback, there's a mistake you cannot do:
function() async {
setState(() {});
myState = await future;
}
This causes a problem because if your future doesn't finish synchronously, build method will be called with an invalid state.
By using the callback you are forced to do the following:
function() async {
final value = await future;
setState(() {
myState = value;
});
}
This time, it doesn't cause problems because the future is awaited before the setState.
Can't I make an async callback and stil have the issue?
No.
Because setState method internally check that the callback does not return a future. And if it does, it will throw