flutter catching errors of nested async methods - dart

I have this method.
asyncFunction1() async {
Firestore.instance.runTransaction((transaction){
var first = await transaction.something;
var second = await secondInside();
});
}
Now I want to call this method, and catch every error that happens inside. How would I propagate errors so that
try {asyncFunction1()}
catch(e){}
catches all errors that happened inside runTransaction?

Your inner function misses an async to be able to use await. If you add it, you can use try/catch
asyncFunction1() {
Firestore.instance.runTransaction((transaction) async {
try {
var first = await transaction.something;
var second = await secondInside();
} catch(e) {
...
}
});
}

Related

FUtureProvider was disposed before value was emitted

I wrote the following code and encountered the error The provider AutoDisposeFutureProvider<Data>#d1e31(465-0041) was disposed before a value was emitted.
I thought it was strange, so I debugged FutureProvider's onDispose and found that it was disposed during the await of the API call, which is confirmed by the output of disposed!
class HogeNotifier extends StateNotifier<Hoge> {
onFormSubmitted(String input) async {
final value = await _reader(searchProvider(input).future); // The provider AutoDisposeFutureProvider<Data>#d1e31(465-0041) was disposed before a value was emitted.
// execute by using value
}
}
final searchProvider =
FutureProvider.autoDispose.family<Data, String>((ref, value) async {
ref.onDispose(() {
print("disposed!");
});
try {
final result = await dataSource.find(keyword: value); //call api asynchronously
return Future.value(result);
} on Exception catch (e) {
return Future<Data>.error(e);
}
});
How can I solve this problem?

Passing Exceptions up the stack in Dart from async to sync methods

So, coming from Javascript world, I can handle exceptions that are thrown however deep down the stack. Doing the same in Dart doesn't work. I'm not sure how to pass exceptions up, to be handled at the root of the stack.
willThrow() async {
throw Exception('Im an exception');
}
init() async {
final illNeverExist = await willThrow();
print(illNeverExist);
}
main() {
try {
init();
} catch(err) {
print(err);
}
}
^^^ This totally works in javascript.
In 'init', even if I wrap that in a try catch, and throw that error, I always get an uncaught exception.
init() async {
try {
final illNeverExist = await willThrow();
print(illNeverExist);
} catch(err) {
throw err
}
}
How do you pass async exceptions up the stack in dart?!
The try-catch block in your main function doesn't wait for your asynchronous init function to complete. Consequently, when init does complete, its exception will no longer be caught.
You can fix this by making main async and using await init();, or you can use Future.catchError to directly register an error callback on the returned Future.

How to use await instead of .then() in Dart

I'm having the following lines in a Flutter app. _devicesRef refers to some node in a Firebase Realtime Database.
_devicesRef.child(deviceId).once().then((DataSnapshot data) async {
print(data.key);
var a = await ...
print(a);
}
These lines work fine. Now I want to use await instead of .then(). But somehow, once() never returns.
var data = await _devicesRef.child(deviceId).once();
print(data.key);
var a = await ...
print (a);
So print(data.key) is never called.
What's wrong here?
It could be explained by the code following your snippet. Perhaps the future completion is trigger by something after your code and transforming your code with await will wait until a completion that never happens.
For instance, the following code works:
main() async {
final c = Completer<String>();
final future = c.future;
future.then((message) => print(message));
c.complete('hello');
}
but not this async/await version:
main() async {
final c = Completer<String>();
final future = c.future;
final message = await future;
print(message);
c.complete('hello');
}
If you intend to use await as a replacement of .then() in your snippet, this is how you can accomplish it:
() async {
var data = await _devicesRef.child(deviceId).once();
print(data.key);
var a = await ...
print(a);
}();
By placing the code in the asynchronous closure () async {}(), we are not preventing execution of the code that comes after, in a similar fashion to using .then().
it should be encased in an async function like this to use await
Furtre<T> myFunction() async {
var data = await _devicesRef.child(deviceId).once();
return data;
}

Recommended way from dart team to catch errors when using await in Flutter

I write a lot of async code that uses await to handle Futures.
If I have
() async {
var result = await someFuture();
}
what would be the preferred way to catch errors. Wraping the code in try/catch or doing
() async {
var result = await someFuture().catch(_errorHandler);
}
EDIT:
Also, if I have many await calls in one async method, what is the preferred catch all the errors instead of writing .catchError for eachOne.
() async {
var result = await someFuture();
var result2 = await someFuture2();
var result3 = await someFuture3();
}
According to the Dart docs if you use await wrap it in a try-catch
According to the Dart docs if you use await wrap it in a try-catch
https://dart.dev/codelabs/async-await#handling-errors
The Docs suggest just wrapping in a try-catch
Example code:
try {
print('Awaiting user order...');
var order = await fetchUserOrder();
} catch (err) {
print('Caught error: $err');
}
Reference also has a runnable example https://dart.dev/codelabs/async-await#handling-errors

returning a value in sync and await in dart

I am trying to understand the usage of async and await in Dart. Somehow I am having issues returning values in certain methods.
Consider the code below
Future<int> getMrn() async {
var mrnRef = await firebaseClient.child('mrn');
DataSnapshot ss;
StreamSubscription<Event> onValueSubscription = await mrnRef.onValue
.listen((event) {
ss = event.snapshot;
return ss.val();
});
//return Future<int> ss.val();
}
mrn is of type int which should be returned by getMrn method. However each time the returned ss.val() returns null. It seems that ss = event.snapshot is not seen in the last returned value
What is the correct way of doing this.
Thanks
In the code above, you're declaring anonymous function (event){..} as a callback, and your return statement relates to it, while your intention was to return from getMrn().
What are you actually need, is to complete a Future you're returning from getMrn() inside your callback.
Like this:
Future<int> getMrn() async {
var mrnRef = await firebaseClient.child('mrn');
Completer<int> c = new Completer<int>();
StreamSubscription<Event> onValueSubscription = await mrnRef.onValue
.listen((event) {
DataSnapshot ss = event.snapshot;
c.complete(ss.val());
});
return c.future;
}
but that code wouldn't work good if there second event appear in mrnRef.onValue stream. So, assuming mrnRef.onValue is a Stream, and you need only first event, it would be better to rewrite it this way:
Future<int> getMrn() async {
var mrnRef = await firebaseClient.child('mrn');
Event event = await mrnRef.onValue.first;
DataSnapshot ss = event.snapshot;
// note, you're implicitly returning a Future<int> here,
// because our function is asyncronous
return ss.val();
}

Resources