Future.then returns unexpected null value - dart

the following method prints a value of a key stored in Redis
Future<String> getValue(String connectionString, String key) {
return RedisClient.connect(connectionString).then((RedisClient client) {
client.get(key).then((value) => print(value));
});
}
but when I try to print the value from main() the method getValue prints null instead of the value (as the method above):
library persistence;
Future<String> getValue(String connectionString, String key) {
return RedisClient.connect(connectionString).then((RedisClient client) {
client.get(key);
});
}
-
import 'package:test/persistence.dart' as persistence;
main () {
persistence.getValue(
"localhost:6379/0",
"key")
.then((value) => print(value)); // **prints null.... WHY???**
}
It seems that the .then((value) => print(value)) is executed too early.
Can anybody help me?

Add a return before client.get(key) or use the short method form => client.get(key) then you don't need the return.

Related

'Future<bool> Function()' can't be assigned to the parameter type 'Future<bool>?'

I'm trying to implement an event callback directly in the constructor, but for some reason it does not compile and I do not understand what's the issue with my code.
abstract class Base {
final Future<bool>? onMagic;
Base({
this.onMagic
});
Future<void> doSomething() async {
if(onMagic != null) {
// does not work... why?
// final useMagic = await onMagic!();
onMagic?.then((magic) {
if(magic) print("TODO make something magical");
});
}
}
}
class RealMagic extends Base {
RealMagic() : super(
// Error: The argument type 'Future<bool> Function()' can't be assigned to the parameter type 'Future<bool>?'.
onMagic: () async => await _magic();
);
Future<bool> _magic() async {
return true;
}
}
I inlined the error above. If that's not possible which alternatives do I have to handle the optional callback?
The problem is with the type of the onMagic. It's not a Future<bool>, it should be a Future<bool> Function()?
abstract class Base {
final Future<bool> Function()? onMagic;
Base({this.onMagic});
Future<void> doSomething() async {
onMagic?.call().then((magic) {
if (magic) print("TODO make something magical");
});
}
}
class RealMagic extends Base {
RealMagic()
: super(
onMagic: () async => await _magic(),
);
static Future<bool> _magic() async { // Made this static so it can be accessed in the constructor
return true;
}
}

How can "A value of type 'void' can t be returned by the 'onError' handler..." on Future.catchError() be avoided?

Here's the simple Dart code which works, but generate a compiler warning:
Future<String> fetchUserOrder() {
return Future.delayed(Duration(seconds: 2), () {
throw UnsupportedError('out of coffee');
// return 'ristretto';
});
}
void main() {
print('main: start');
fetchUserOrder()
.then((value) {
print(value);
})
.catchError((error) => print(error.message)) // DISPLAYED WARNING: A value of type 'void' can t be returned by the 'onError' handler because it must be assignable to 'FutureOr<Null>'.
.whenComplete(() => print('complete'));
}
How is it possible to avoid the compiler warning "A value of type 'void' can t be returned by the 'onError' handler because it must be assignable to 'FutureOr'." displayed on the catchError line ?
The direct way is to use an async function:
void main() async {
print('main: start');
try {
var value = fetchUserOrder();
print(value);
} catch (error) {
print((error as dynamic).message);
} finally {
print('complete'));
}
}
If you want to use Future methods instead, you can make the then call return a Future<void> as:
void main() {
print('main: start');
fetchUserOrder()
.then<void>((value) {
print(value);
})
.catchError((error) => print(error.message))
.whenComplete(() => print('complete'));
}
I'd probably personally go with including the catchError in the then call:
void main() {
print('main: start');
fetchUserOrder().then<void>((value) {
print(value);
}, onError: (dynamic error) {
print(error.message);
}).whenComplete(() => print('complete'));
}
Using then allows you to set the required return type of the onError callback, and it can be used even when there is no value callback, as:
someFuture.then<void>((_){}, onError: (e, s) {
do something without returning a value;
});

Flutter and Firebase: How can i receive data from function?

i use the following function to fetch userData from Firestore:
Future<String>getRegisterUserData({String userID}) async {
Firestore.instance.collection("Users").document(userID).get().then(
(datasnapshot) {
if (datasnapshot.exists) {
return datasnapshot.data['Email'];
} else {
return "Loading...";
}
},
);
}
I execute this function on my UserProfilePage like this:
_email = widget.firestore.getRegisterUserData(widget.userID).toString();
But i always get the print statement: Instance of 'Future' and not the saved email-address...
i also try this:
Future<String> getRegisterUserData({String userID}) async {
String email;
Firestore.instance.collection("Users").document(userID).get().then(
(datasnapshot) {
if (datasnapshot.exists) {
email = datasnapshot.data['Email'];
} else {
email = "Loading...";
}
},
);
return email;
}
The Print Statement is always the same...
So where is my mistake? I want to display the Value of 'Email' on the UserProfilePage in a variable, or is my firestore function incorrect?
Thank you for our help
Add await keyword. But at a different place.
tempEmail = await widget.firestore.getRegisterUserData(widget.userID);
setState(() {
_email = tempEmail;
});
// we don't need toString as getRegisterUserData itself is returning Future<String>
Note for using await: As we are using await the method/function which contains this should have a async in its signature.
Or you can use then block
widget.firestore.getRegisterUserData(widget.userID).then((email) {
setState(() {
_email = email;
});
});
Explanation: widget.firestore.getRegisterUserData(widget.userID) is of type Future<String>. that's why it is printed as Instance of 'Future'. We have to convert the Future to String by await or by then block
Using SharedPreferences:
Future<String> getEmail() async {
final prefs = await SharedPreferences.getInstance();
String email = prefs.getString('email');
if (email != null) {
return email;
} else {
email = await widget.firestore.getRegisterUserData(widget.userID);
prefs.setString('email', email); //update shared preferences
return email;
}
}
// usage (may be in initState)
widget.getEmail().then((email) {
setState(() {
_email = email;
})
})
Updated
Based on your information, you need a FutureBuilder in order to wait the response to build your widget:
return FutureBuilder(
future: getRegisterUserData(userID: "1234"),
builder: (context, asyncsnapshot){
return asyncsnapshot.hasData && asyncsnapshot.data != null ? TextFormField(
initialValue: asyncsnapshot.data,
) : CircularProgressIndicator();
}
);

Obscure Dart syntax

While working through the the Dart Route library example for client side coding I came across this snippet.
var router = new Router()
..addHandler(urls.one, showOne)
..addHandler(urls.two, showTwo)
..addHandler(urls.home, (_) => null)
..listen();
My question is how does (_) => null work? It seems to specify a function that returns a null value but what does (_) mean?
(_) means it is a function with one parameter but you don't care about that parameter, so it's just named _. You could also write (ignoreMe) => null. The important thing here is, that there needs to be a function that accepts one parameter. What you do with it, is your thing.
(_) => null means : a function that take one parameter named _ and returning null. It could be seen as a shortcut for (iDontCareVariable) => null.
A similar function with no parameter would be () => null.
A similar function with more parameters would be (_, __, ___) => null.
Note that _ is not a special syntax defined at langauge level. It is just a variable name that can be used inside the function body. As example : (_) => _.
I will try explain this by the example.
void main() {
var helloFromTokyo = (name) => 'こんにちわ $name';
var greet = new Greet();
greet.addGreet('London', helloFromLondon)
..addGreet('Tokyo', helloFromTokyo)
..addGreet('Berlin', helloFromBerlin)
..addGreet('Mars', (_) => null)
..addGreet('Me', (name) => 'Privet, chuvak! You name is $name?')
..addGreet('Moon', null);
greet.greet('Vasya Pupkin');
}
String helloFromLondon(String name) {
return 'Hello, $name';
}
String helloFromBerlin(String name) {
return 'Guten tag, $name';
}
class Greet {
Map<String, Function> greets = new Map<String, Function>();
Greet addGreet(String whence, String sayHello(String name)) {
greets[whence] = sayHello;
return this;
}
void greet(String name) {
for(var whence in greets.keys) {
var action = greets[whence];
if(action == null) {
print('From $whence: no reaction');
} else {
var result = action(name);
if(result == null) {
print('From $whence: silent');
} else {
print('From $whence: $result');
}
}
}
}
}
Output:
From London: Hello, Vasya Pupkin
From Tokyo: こんにちわ Vasya Pupkin
From Berlin: Guten tag, Vasya Pupkin
From Mars: silent
From Me: Privet, chuvak! You name is Vasya Pupkin?
From Moon: no reaction

indexed_db openCursor latest changes

The following code was posted as the new handling for openCursor. Could someone please advise if the following code should work now (Dart r18915), and what is the "values" variable?
store.openCursor(autoAdvance: true).listen(
(cursor) => values.add(onCursor(cursor)),
onDone: () => completer.complete(values),
onError: (e) => completer.completeError(e));
return completer.future;
I'm not sure what your onCursor() function is doing/calling. I'm assuming your values variable is a list.
I do something similar myself but with a callback instead of a future/completer. You only have a small function fragment here. I'm going to flush it out some to hopefully add some details:
// Accept the indexeddb Database, and return a future which
// will provide the list of values from 'someKey'
Future<List<String>> getSomeKeyValues(Database db) {
var values = new List<String>();
var completer = new Completer();
var store = db.transaction('DB_STORE', 'readwrite').objectStore('DB_STORE');
store.openCursor(autoAdvance: true).listen((cursor) {
if(cursor != null && cursor.value != null) {
// Note cursor.value is actually a Map<String, String>
// of collection's key and value
values.add(cursor.value['someKey']); // get the value key 'someKey'
}
}, onDone: () => completer.complete(values),
onError: (e) => completer.completeError(e));
return completer.future;
}
We would then call this function something like this:
getSomeKeyValues(myDatabase).then((results) {
for(var value in results) {
print(value);
}
}

Resources