How can we get value from future method in flutter? - flutter

I have this function returning the "SharedPreference" value stored in it.
Future<bool> getLoginStatus() async {
final prefs = await SharedPreferences.getInstance();
final loggedInStatus = prefs.getBool("loggedInStatus");
if (loggedInStatus == null) {
return false;
}
return loggedInStatus;
}
Above function is in the class named "Constants.dart". When I do the test of extracting value from "getLoginStatus()" function by simple printing in different class.
print("Login status : " + Constants().getLoginStatus().toString());
It give me below as an output. Why "Instance of 'Future'"? Why not simple either true or false?
I/flutter (19683): Login status : Instance of 'Future<bool>'

Since your getLoginStatus() is asynchronous and it return a bool value in future. So to get the value you have to await for the process to return it.
So the correct Code to retrieve the value would be :
bool loggedInStatus = await Constants().getLoginStatus();
print(loggedInStatus);

getLoginStatus().then((val){ print("Login status : $val"});
The then function should be used with Futures to access the value returned from a future.

you can get data using await.
var data = await Constants().getLoginStatus();
print(data);

Related

Unhandled Exception: type 'Null' is not a subtype of type 'List<dynamic>' in type cast

Objective is to convert a String to List using map and return the value to a function call.
I am using SharedPreferences to save a list of object called where in I save the data at a point and get the data when it is to be put on view.
The below block is the function where the error is occurring.
void getData() async {
final prefs = await SharedPreferences.getInstance();
final String taskString = prefs.getString('task_data').toString();
List<Task> tasksData = Task.decode(taskString);
_tasks = tasksData;
notifyListeners();
}
decode() looks basically does the conversion.
static List<Task> decode(String tasks) {
return (jsonDecode(tasks) as List<dynamic>).map<Task>((task) {
return Task.fromJson(task);
}).toList();
It advises to check for null condition in type cast of decode(). But on performing the check, it gives the same error.
your response might be not a proper map so it cannot decode that data using the jsonDecode function so it returns Null, so you can use your function like this might be helpful for you :
static List<Task> decode(String tasks) {
var data = (jsonDecode(tasks) as List<dynamic>?);
if(data != null){
return (jsonDecode(tasks) as List<dynamic>?)!.map<Task>((task) {
return Task.fromJson(task);
}).toList();
} else {
return <Task>[];
}
}

How to have a flutter class method return a future?

How do I set up a flutter method to return a future value that is drawn from the results of a future http post call inside the method?
The example code below is making a call to a web URL to add a new product. I want this method to return just the Id of the newly created product (i.e. 'name' inside response)
Future<String> add(Product aNewProduct) async {
var aUrl = Uri.parse(dbUrl);
http.post(aUrl,body: toBody(aNewProduct),).then((response) {
var aStr = json.decode(response.body)['name'];
return Future<String>.value(aStr);
});
}
With the code above, the parser is showing the following error/warning...
The body might complete normally, causing 'null' to be returned,
but the return type, 'FutureOr<String>', is a potentially non-nullable type.
(Documentation) Try adding either a return or a throw statement at the end.
Any suggestions on how to fix this?
You can use the await to get the value of a Future or rather your http request. After that you can simple decode it and return your desired behavior.
Future<String> add(Product aNewProduct) async {
var aUrl = Uri.parse(dbUrl);
final response = http.post(
aUrl,
body: toBody(aNewProduct),
);
return json.decode(response.body)['name'];
}
try this:
Future<String> add(Product aNewProduct) async {
var aUrl = Uri.parse(dbUrl);
var response= await http.post(aUrl,body: toBody(aNewProduct),);
if(response.statusCode==200){
var rawData = await response.stream.bytesToString();
Map data=json.decode(rawData);
return data['name'];
}else{
return '';
}
}
It is as simple as putting a return before the http.post statement

Flutter - await/async on a List - why does this only work when not using declarations?

Still new to Flutter :(. Can anyone help...
I have a class that stores a bunch of project information. One part of this is a list of topics (for push notification), which it grabs from a JSON file.
I apply a getter for the list of topics, and when getting it it calls an async function which will return a List
Future<List<String>> _pntopics() async{
final _json = await http.get(Uri.parse(_topicsUrl));
if (_json.statusCode == 200) {
return (jsonDecode(_json.body));
}else {
return [""];
}
}
Future<List<String>> get topics => _pntopics();
In my main.dart file, it calls this value like so...
Future<List<String>> _topiclist = await projectvalues.topics;
The response is however empty, pressumably because it is a Future - so it is grabbing the empty value before it is filled.
But I can't remove the "Future" part from the async method, because asnc methods require a Future definition.
Then I decided to remove the declarations entirely:
_pntopics() async{
final _json = await http.get(Uri.parse(_topicsUrl));
if (_json.statusCode == 200) {
return (jsonDecode(_json.body));
}else {
return [""];
}
}
get topics => _pntopics();
and in main.dart, a general declaration...
var _topiclist = await projectvalues.topics;
...and this works!
So what declaration should I actually be using for this to work? I'm happy to not use declarations but we're always to declare everthing.
You should return back Future<List<String>> return types to the function and the getter but for _topicslist you must use var, final or List<String> declaration because:
(await Future<T>) == T
i.e.
var _topiclist = await projectvalues.topics; // The type of _topiclist is List<String>
final _topiclist = await projectvalues.topics; // The type of _topiclist is List<String>
UPDATE
Your code should be:
Future<List<String>> _pntopics() async{
final _json = await http.get(Uri.parse(_topicsUrl));
if (_json.statusCode == 200) {
return List<String>.from(jsonDecode(_json.body));
}else {
return <String>[""];
}
}
Doing this you force _pnptopics returns List<String> as jsonDecode returns List<dynamic>.
P.S. It is good practice do not use dynamic types where they can be changed to specified types.

returning a String when getting error: type 'Future<dynamic>' is not a subtype of type 'String'

I can't work out how to return a string from a function in Dart (a Flutter app).
I am using SharedPreferences to capture input from the user. I have two functions, one to save preferences:
save(key, value) async {
final prefs = await SharedPreferences.getInstance();
prefs.setString(key, value);
print('saved $value');
}
and one to read preferences:
read(key) async {
final prefs = await SharedPreferences.getInstance();
final value = prefs.getString(key) ?? 0;
print('$value');
}
This is working, but when I try to replace the print line with a return:
read(key) async {
final prefs = await SharedPreferences.getInstance();
final value = prefs.getString(key) ?? 0;
return('$value');
}
to return a string for the value, it throws an error:
type 'Future' is not a subtype of type 'String'
I have tried calling it many MANY different ways, but can't figure out what I assume is an incredibly basic problem. I noticed in some posts that this is a suggested solution, which works to print out the value, but I don't want to print it, i want it as a String variable:
read(mykey).then((value) => '$value');
I need to combine the value with other some other string values and make some minor manipulations (so printing it isn't helpful)
UPDATE
I have defined the function as #Stijn2210 suggested, but am still having problems getting the output i need.
Future<String> read(key) async {
final prefs = await SharedPreferences.getInstance();
final value = await prefs.getString(key) ?? '';
return value;
}
When I call this function from my app (this is a simplified snippet):
void onDragEnd(DraggableDetails details, User user) {
final minimumDrag = 100;
Future<String> myvalue;
if (details.offset.dx > minimumDrag) {
user.isSwipedOff = true;
save(user.imgUrl, 'Dog');
}
myvalue = read(user.imgUrl);
print(myvalue);
It's printing :
Instance of 'Future'
Whereas I want myvalue to be 'Dog'... Appreciate any insights!!
Really appreciate your answer #Stijn2202
Solution was to edit the method definition:
Future<void> onDragEnd(DraggableDetails details, User user) async
and then call the read function from the method with this:
final String myvalue = await read(user.imgUrl);
getString is a Future, which you can handle by using await or as you are doing, using then
However, in my opinion using await is your better option. This would look like this:
Future<String> getMyString() async {
final prefs = await SharedPreferences.getInstance();
final value = await prefs.getString(key) ?? '';
// Don't use 0, since it isnt an int what you want to return
return value;
}
EDIT:
based on your code snippet, this is how you should call your read method:
Future<void> onDragEnd(DraggableDetails details, User user) async {
final minimumDrag = 100;
if (details.offset.dx > minimumDrag) {
user.isSwipedOff = true;
save(user.imgUrl, 'Dog');
}
final String myvalue = await read(user.imgUrl);
print(myvalue);
}
Now I'm not sure if onDragEnd is actually allowed to be Future<void>, but let me know if it isn't
Just await for the value. It will return Dog and not instance of Future.
String someName=await myvalue;
As the value is Future, await keyword will wait until the task finishes and return the value

Flutter - Retrieve value in getter outside of a .then() function

I´ve created a get method outside the Widget tree to retrieve a value from a database provider. But the problem: Because it is a Future type I have to get this data with .then() ..and outside of .then() my return does not know this value.
Example:
String get _plannedHours {
final calendarEntriesData =
Provider.of<CalendarEntries>(context, listen: false);
calendarEntriesData.getPlannedHoursFromMonth(_currentDate).then((value) {
print(value.length); // I need this value
});
return "Value: 20"; // ....here!
}
How I get this value outside of .then() to return a value to the Widget three?
You can use async/await to access the value:
Future<String> get _plannedHours async {
final calendarEntriesData =
Provider.of<CalendarEntries>(context, listen: false);
var value = await calendarEntriesData.getPlannedHoursFromMonth(_currentDate);
return "Value: ${value.length}";
}
Then you need to do:
await _plannedHours