Flutter: Error: 'await' can only be used in 'async' or 'async*' methods. even thought the method is async - flutter

I have this method:
Future<AppUser> _getUser(String documentId) async {
var document = await firestore.collection('customers').doc(documentId);
document.get().then((DocumentSnapshot documentSnapshot) {
print(documentSnapshot.data());
});
AppUser bruceUser = AppUser(userId: 'user006',);
return bruceUser;
}
And below it, I have a variable that uses this method:
AppUser _user = await _getUser(document.id);
However, this returns the following error:
Error: 'await' can only be used in 'async' or 'async*' methods.
What am I doing wrong here? I don't want to change _user to Future, because it will complicate the code further, so why doesn't the await work?

_getUser() is an asnyc function but not the calling function.
The error you are getting states that, await was used in a non-async function.
If you have difficulty in converting the caller function to async, try using then as follows.
snapshot.data.docs.map((DocumentSnapshot document) {
_getUser(document.id).then((user) {
//code here
});
}
In summary, there are two solutions for this
Convert the caller function to async.
Use _getUser().then((user){});

Related

Flutter Riverpod Future provider - requires async and await?

I've been reviewing the RiverPod 2 tutorial at https://codewithandrea.com/articles/flutter-state-management-riverpod/
In the section dealing with Future providers there is a code snippet as shown below...
final weatherFutureProvider = FutureProvider.autoDispose<Weather>((ref) {
// get repository from the provider below
final weatherRepository = ref.watch(weatherRepositoryProvider);
// call method that returns a Future<Weather>
return weatherRepository.getWeather(city: 'London');
});
I can't understand why this code snippet is missing the 'async' and 'await' syntax as shown below...
final weatherFutureProvider = FutureProvider.autoDispose<Weather>((ref) async {
// get repository from the provider below
final weatherRepository = ref.watch(weatherRepositoryProvider);
// call method that returns a Future<Weather>
return await weatherRepository.getWeather(city: 'London');
});
Is my version correct or what?
Think of it as doing:
Future<int> example() {
return Future.value(42);
}
instead of:
Future<int> example() async {
return await Future.value(42);
}
Sure, you can use async/await. But it is technically optional here.
Doing return future vs return await future doesn't change anything. In fact, there's a lint for removing the unnecessary await: unnecessary_await_in_return
The async keyword is generally helpful. It catches exceptions in the function and converts them into a Future.error.
But FutureProvider already takes care of that. So async could also be omitted

How can flutter test frame work be used to test Clipboard?

How can I test code that uses Clipboard in Dart. It will not work from the test framework.
The code works well when run from a main programme (after runApp(..)). But the following test fails
This is the code I want to test:
Future setText(String input) async {
ClipboardData data = ClipboardData(text: input);
await Clipboard.setData(data);
if (!await Clipboard.hasStrings()) {
if (kDebugMode) {
print("Added string, no strings!"); //
}
}
}
Future<String?> getText() async {
if (await Clipboard.hasStrings()) {
ClipboardData? result = await Clipboard.getData(Clipboard.kTextPlain);
if (result == null) {
return null;
}
return result.text;
}
return null;
}
I have test code...
void main() async {
test("Test copying data to and from the clipboard", () async {
TestWidgetsFlutterBinding.ensureInitialized();
String testStringPut = "ABC def 123 ";
await setText(testStringPut);
String? testStringGet = await getText();
expect(testStringGet, testStringPut);
});
}
The line: TestWidgetsFlutterBinding.ensureInitialized(); is some sort of magic incantation as far as I know, and is probably where my problem lies.
Without it I get the error:
Exception has occurred.
FlutterError (Binding has not yet been initialized.
The "instance" getter on the ServicesBinding binding mixin is only available once that binding has been initialized.
Typically, this is done by calling "WidgetsFlutterBinding.ensureInitialized()" or "runApp()" (the latter calls the former). Typically this call is done in the "void main()" method. The "ensureInitialized" method is idempotent; calling it multiple times is not harmful. After calling that method, the "instance" getter will return the binding.
In a test, one can call "TestWidgetsFlutterBinding.ensureInitialized()" as the first line in the test's "main()" method to initialize the binding.
If ServicesBinding is a custom binding mixin, there must also be a custom binding class, like WidgetsFlutterBinding, but that mixes in the selected binding, and that is the class that must be constructed before using the "instance" getter.)

Flutter Future<void> vs Future<Null> vs void

What is the main difference between:
Future<void> function(){}
Future<Null> function(){}
void function() {}
funtion(){}
Sometimes I use void or future when calling the API but I don't really know what the main difference is and when is the right time to use it?
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?
Future<Null> function() {}
Defines an asynchronous function that ultimately returns null when it eventually completes. Don't use this; this is an archaic form of Future<void>. It predates Dart 2 and was necessary because void was not yet a proper type, and there was no mechanism for indicating that a Future should return nothing. Also see: Dart 2: Legacy of the void
void function() {}
Defines a function that returns nothing. If the function does asynchronous work, callers will not be able to directly tell when it is complete.
function() {}
Defines a function with an unspecified return type. The return type is implicitly dynamic, which means that the function can return anything. Don't do this since it does not convey intent; readers will not be able to tell if the return type was omitted intentionally or accidentally. It also will trigger the always_declare_return_types lint. If you actually want to return a dynamic type, you should explicitly use dynamic function() {} instead.
By default, a function likes function() {} returns a null pointer value.
Use this archetype when your function not return anything and it's not marked as async:
function() { // <- not async
// ... some code
// ... don't use return
}
Optionally, you can specify not return values using void function() {} sintaxis. It's same at the function() {} but if you try to assign a value after calling you will get an error in compile time:
Error: This expression has type 'void' and can't be used.
Personally, i recommend this approach if you really don't have a return value and the function it's not async.
Note that you can use void in normal and async functions.
A function likes Future<void> function() async {} is for asynchronous function thats returns a Future<void> object.
I personally recommend the void function() async {} only if you don't use await ot then on call your function, otherwise, use Future <void> function() async {}.
An examples:
Future<void> myFunction() async {
await Future.delayed(Duration(seconds: 2));
print('Hello');
}
void main() async {
print(myFunction()); // This works and prints
// Instance of '_Future<void>'
// Hello
// Use this approach if you use this:
myFunction().then(() {
print('Then myFunction call ended');
})
// or this
await myFunction();
print('Then myFunction call ended');
}
void myFunction() async {
await Future.delayed(Duration(seconds: 2));
print('Hello');
}
void main() async {
print(myFunction()); // This not works
// The compile fails and show
// Error: This expression has type 'void' and can't be used.
// In this case you only can call myFunction like this
myFunction();
// This doesn't works (Compilation Error)
myFunction().then(() {
print('Then myFunction call ended');
});
// This doesn't works (Compilation Error)
await myFunction();
print('Then myFunction call ended');
}
A function likes Future<Null> function() async {} returns a Future<null> object. Use it whenever you return null. It's not recommended to use it because class Null not extends from Object and anything you return marks an error (except statements thats returns a null or explicit null value):
Future<Null> myFunction() async {
await Future.delayed(Duration(seconds: 2));
print('Hello');
// Ok
return (() => null)();
// Ok
return null;
}

Dart Flutter, help me understand futures

See this code:
class SomeClass{
String someVariable;
SomeClass();
Future<String> getData () async {
Response response = await get('http://somewebsite.com/api/content');
Map map = jsonDecode(response.body); // do not worry about statuscode, trying to keep it minimal
someVariable = map['firstName'];
return 'This is the first name : $someVariable';
}
}
Now look at main:
void main(){
String someFunction() async {
SomeClass instance = SomeClass(); // creating object
String firstNameDeclaration = await instance.getData().then((value) => value);
return firstNameDeclaration;
}
}
When working with Future, like in the case of firstNameDeclaration why do I have to use .then() method to access the string object, since I am waiting for the function to finish?
When searching on the web, some people use .then() others don't, I am confused.
Kindly help me have a clearer understanding of how Futures and async functions overall work.
Background
Asynchronous operations let your program complete work while waiting for another operation to finish. Here are some common asynchronous operations:
Fetching data over a network.
Writing to a database.
Reading data from a file.
To perform asynchronous operations in Dart, you can use the Future class and the async and await keywords.
When an async function invokes "await", it is converted into a Future, and placed into the execution queue. When the awaited future is complete, the calling function is marked as ready for execution and it will be resumed at some later point. The important difference is that no Threads need to be paused in this model.
Futures vs async-await
When an async function invokes "await", it is converted into a Future, and placed into the execution queue. When the awaited future is complete, the calling function is marked as ready for execution and it will be resumed at some later point. The important difference is that no Threads need to be paused in this model.
async-await is just a a declarative way to define asynchronous functions and use their results into Future and it provides syntactic sugar that help you write clean code involving Futures.
Consider this dart code snipped involving Futures -
Future<String> getData(int number) {
return Future.delayed(Duration(seconds: 1), () {
return 'this is a future string $number.';
});
}
main(){
getData(10).then((data) => {
print(data)
});
}
As you can see when you use Futures, you can use then callback when the function return a future value. This is easy to manage if there is single "then" callback but the situation escalates quickly as soon as there are many nested "then" callbacks for example -
Future<String> getProductCostForUser() {
return getUser().then((user) => {
var uid = user.id;
return getOrder(uid).then((order) => {
var pid = order.productId;
return getProduct(pid).then((product) => {
return product.totalCost;
});
});
});
}
main(){
getProductCostForUser().then((cost) => {
print(cost);
});
}
As you can when there multiple chained "then" callback the code become very hard to read and manage. This problem is solved by "async-await". Above chained "then" callbacks can be simplified by using "async-await" like so -
Future<String> getProductCostForUser() async {
var user = await getUser();
var order = await getOrder(user.uid);
var product = await getProduct(order.productId);
return product.totalCost;
}
main() async {
var cost = await getProductCostForUser();
print(cost);
}
As you can above code is much more readable and easy to understand when there are chained "then" callbacks.
I hope this explains some basic concepts and understanding regarding the "async-await" and Futures.
You can further read about topic and examples here
Basically, you should either use await OR then(). However, Dart guidelines advocates that you should prefer use await over then() :
This code :
Future<int> countActivePlayers(String teamName) {
return downloadTeam(teamName).then((team) {
if (team == null) return Future.value(0);
return team.roster.then((players) {
return players.where((player) => player.isActive).length;
});
}).catchError((e) {
log.error(e);
return 0;
});
}
should be replaced by :
Future<int> countActivePlayers(String teamName) async {
try {
var team = await downloadTeam(teamName);
if (team == null) return 0;
var players = await team.roster;
return players.where((player) => player.isActive).length;
} catch (e) {
log.error(e);
return 0;
}
}
In your case, you should write :
void main(){
Future<String> someFunction() async {
SomeClass instance = SomeClass(); // creating object
String firstNameDeclaration = await instance.getData();
return firstNameDeclaration;
// Or directly : return await instance.getData();
// Or : return instance.getData();
}
}

Dart: I made a function async but still can't use await

I made a function async but still can't use await expression. What am I wrong? My code is like this.
Future<void> _aFunction() async {
DocumentReference docRef = Firestore.instance.collection('collection').document(docId);
docRef.get().then((DocumentSnapshot docSnapShot) {
if (docSnapShot.exists) {
String ip = await Connectivity().getWifiIP();
That's because here is an internal (anonymous) function declaration inside then, which is not async. Actually, await keyword can be thought as a syntactic sugar over then, so it would be convenient to refactor the function like this:
Future<void> _aFunction() async {
final DocumentSnapshot snapshot = await Firestore.instance.collection('collection').document(docId).get();
if (snapshot.exists) {
String ip = await Connectivity().getWifiIP();
// Rest of the `ip` variable handling logic function
}
// Rest of the function
}
Now await keyword corresponds to the _aFunction itself instead of an anonymous function declared inside _aFunction, so it works as expected.