FUtureProvider was disposed before value was emitted - flutter-riverpod

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?

Related

Generate a stream from another stream result

I have a stream I want to map the result of that stream to another stream and return the mapped stream.
Stream<SomeClass> subscribe() async* {
final Stream<Map<String, dynamic>> baseStream = api.subscribeToSomething(id: id);
baseStream.listen(
(Map<String, dynamic> response) {
if (response.containsKey('error')) {
throw Exception(response['error']['message']);
} else {
yield SomeClass.fromMap(response['result']);
}
},
);
}
but I get this error:
The method 'yield' isn't defined for the class 'SomeClass'. Try
correcting the name to the name of an existing method, or defining a
method named 'yield'.
question is how can I map a stream to another stream and return result stream?
Thanks to julemand101, the solution is:
Stream<SomeClass> subscribe() =>
api.subscribeToSomething(id: id).map<SomeClass>(
(Map<String, dynamic> response) {
if (response.containsKey('error')) {
throw Exception(response['error']['message']);
} else {
return SomeClass.fromMap(response['result']);
}
},
);
Use an await-for to listen for events:
Stream<SomeClass> subscribe() async* {
final Stream<Map<String, dynamic>> baseStream = api.subscribeToSomething(id: id);
await for (var response in baseStream) {
if (response.containsKey('error')) {
throw Exception(response['error']['message']);
} else {
yield SomeClass.fromMap(response['result']);
}
}
}
The await for will forward pauses and resumes correctly to the base stream, and it will make errors in the base stream terminate the loop.
(Also, consider creating a subclass of Exception for your excepsions, so your users can catch and handle those specifically, rather than having to catch all exceptions).

Why omitting the await keyword results in different behavior?

I am testing some middleware code. When the function middleware.call is provoked I get different results depending on whether I use the keyword await when calling it.
This is testing code:
final actionLog = <dynamic>[];
final Function(dynamic) next = (dynamic action){
actionLog.add(action);
};
test('Fetching a dictionary entry successfully', () async {
DictionaryEntry dictionaryEntry = new DictionaryEntry(2333, 'after', null, null);
when(
mockApi
.getDictionaryEntry('after', any, any)
).thenAnswer((_) => Future.value(dictionaryEntry));
final action = FetchDictionaryEntryAction('after');
await dictionaryMiddleware.call(mocksStore, action, next);
// length of action log is 2
// when I don't use await before calling dictionaryMiddleware.call
// but its 4 when using await before calling the function.
print("length of action log " + actionLog.length.toString());
print(actionLog);
});
This is the middleware:
#override
Future<void> call(
Store<AppState> store, dynamic action, NextDispatcher next) async {
next(action);
if(action is FetchDictionaryEntryAction){
await _fetchDictionaryEntry(action.speechText,
action.fromLanguage, action.toLanguage, next
);
}
}
Future<void> _fetchDictionaryEntry(
String speechText,
String fromLanguage,
String toLanguage,
NextDispatcher next
) async {
if(speechText == null || speechText?.length == 0){
next(ReceivedDictionaryEntryAction(dictionaryEntry: null));
return;
}
next(RequestingDictionaryEntryAction());
try{
final DictionaryEntry dictionaryEntry =
await this.api.getDictionaryEntry(speechText, fromLanguage, toLanguage);
next(ReceivedDictionaryEntryAction(dictionaryEntry: dictionaryEntry));
next(CacheDictionaryEntryAction(dictionaryEntry));
}catch(e){
next(ErrorLoadingDictionaryEntryAction);
}
}
I am wondering why does next() (the dispatcher in the middleware) get called only 2 times when not using await as apposed to getting called 4 times when using await which is the normal behavior.

flutter catching errors of nested async methods

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

Returning a String from an async

I want to return a String from an async function but I get a Future
What am I doing wrong;
Example
main() {
String s;
s = dummy("http://www.google.com");
}
String dummy(String s) {
String response;
response = readURL(s);
return response;
}
Future<String> readURL(String requestString) async {
String response = await http.read(requestString);
print(response);
return response;
}
Error:
type '_Future' is not a subtype of type 'String' of 'response'.
A function that's annotated with async will always return a Future.
so when you call readUrl(s) you can await its result.
To use await, the caller (here your main function) has to be marked as async. So the end result could look like this:
main() async {
String s = await dummy("http://www.google.com");
}
Future<String> dummy(String s) async {
String response = await readURL(s);
return (response);
}
Future<String> readURL(String requestString) async {
String response = await http.read(requestString);
print(response);
return(response);
}
The thing to notice here: If you use await in a function, it is now considered as function that returns a Future. So every function you convert to be async will now return a Future.
Here is the Simple Two way to get value from Function with return type Future<Type>
1- First way (best way, as you call this code from any file)
FutureFunctionName.then((val) {
val contains data
});
For example- (I am posting one from real example)
Future<String> getUserAgents() async {
String userAgent;
await FlutterUserAgent.init();
userAgent = FlutterUserAgent.webViewUserAgent;
return userAgent;
}
String userAgent;
getUserAgents().then((val) {
userAgent = val;
});
print(userAgent); // you will get output
2- Second way (use a global variable to get data)
String userAgent;
Future<void> getUserAgents() async {
await FlutterUserAgent.init();
userAgent = FlutterUserAgent.webViewUserAgent;
}
print(userAgent);

How return Future from Future? Or this is prohibited in async library?

How I can return Future value from Future object?
This code does not work.
import 'dart:async';
void main() {
var temp = foo();
temp.then((Future<int> future) {
future.then((int result) {
print(result);
});
});
}
Future<Future<int>> foo() {
return new Future<Future<int>>(() {
return new Future<int>(() => 5);
});
}
How to prevent unnecessary unwrapping?
In this case in async library 'Future' declared as generic class.
abstract class Future<T> {
}
If I create expression as the following
new Future<Future<int>>();
Then with type T specified as Future<int> which result expected from generic class Future?
I thing that result must be as specified in type argument T.
I.e. Future<int>.
But result is not as expected.
There is no information found about this abnormal behavior on Dart API site.
If this is a "feature" (but I think that abnormal behavior wrongly to call "feature') then why it not documented in Dart API?
How can be explained this discrepancy?
Why this code not generated errors and warnings?
Another IDENTICAL example but w/o using Future.
void main() {
var temp = foo();
temp.baz((Foo<int> foo) {
foo.baz((int result) {
print(result);
});
});
}
Foo<Foo<int>> foo() {
return new Foo<Foo<int>>(() {
return new Foo<int>(() => 5);
});
}
If in this case result will be as when using Future (i.e. unexpected) then how we can call this code?
Normal or abnormal?
Or maybe the Future in Dart some special (magic)?
Look at the api documentation
http://api.dartlang.org/docs/releases/latest/dart_async/Future.html
It says there:
If the returned value is itself a Future, completion of the created future will wait until
the returned future completes, and will then complete with the same result.
I guess that means you can't return a Future from a Future.
But you could return a list of futures.
void main() {
var temp = foo();
temp.then((List<Future<int>> list) {
list[0].then((int result) {
print(result);
});
});
}
Future<List<Future<int>>> foo() {
return new Future<List<Future<int>>>(() {
return [new Future<int>(() => 5)];
});
}
There is no need for any of that extra wrapping. According to the Future documentation:
If the returned value is itself a [Future], completion of the created
future will wait until the returned future completes, and will then
complete with the same result.
This means you can rewrite your code as:
import 'dart:async';
void main() {
var temp = foo();
temp.then((int result) {
print(result);
});
}
Future<int> foo() {
return new Future<int>(() {
return new Future<int>(() => 5);
});
}
This is a lot cleaner to work with and provides the expected result.

Resources