Dart: A value of type 'String?' can't be assigned to a variable of type 'String' - flutter

There are 2 functions. One must return String other save this String in with SharedPreferences.
The problem is, that by using prefs.getString() I get not a String but another object.
The error called: A value of type 'String?' can't be assigned to a variable of type 'String'.
getCurrentCityFromSharedPreferences() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
return prefs.getString('currentCity');
}
Future<void> setCurrentCityInSharedPreferences(String newCity) async{
final prefs = await SharedPreferences.getInstance();
prefs.setString('currentCity', newCity);
}
I have tried to rewrite function to
Future<String?> getCurrentCityFromSharedPreferences() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
return prefs.getString('currentCity');
}
but then I get as string Deskription of object: Instance of 'Future<String?>'

your set string type is simply string and get type is String?
so change set type like this
Future<void> setCurrentCityInSharedPreferences(String? newCity) async{
final prefs = await SharedPreferences.getInstance();
prefs.setString('currentCity', newCity!);
}

When you try to get currentCity from SharedPreferences you get an object of type String?. This basically means that the returned object is a string that can also be null (in case there is no data stored with the key currentCity in SharedPreferences).
So, you can't do something like:
String s = prefs.getString('currentCity');
You have to handle the possibility of the value being null.
You can either declare the variable as String? like this:
String? s = prefs.getString('currentCity');
Or you can do something like:
String s = prefs.getString('currentCity') ?? "No City";
So, if you want to handle null values in the getCurrentCityFromSharedPreferences function then what you can do is:
Future<String> getCurrentCityFromSharedPreferences() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
return prefs.getString('currentCity') ?? "No City";
}
You can replace "No City" with any value that you want to show when there is no city saved in SharedPreferences.

Related

How to save a list to shared preferences

I want to save a list to shared preferences, but it doesn't work... The goal is to add data to the variable and save it.
This is the variable I want to save:
var savedData = [
{'date': 0, 'testNumber': 0},
];
And this is the code I tried for saving and receiving the variable:
Future<void> saveDataTest() async {
final prefs = await SharedPreferences.getInstance();
await prefs.setStringList(
'dataTest', savedData.map((i) => i.toString()).toList());
}
Future<String> getDataStringTest() async {
final prefs = await SharedPreferences.getInstance();
savedData =
prefs.getStringList('dataTest').map((i) => int.parse(i)).toList();
setState(() {});
}
This is the error I get:
A value of type 'List<int>' can't be assigned to a variable of type 'List<Map<String, int>>'.
Try changing the type of the variable, or casting the right-hand type to 'List<Map<String, int>>'.
As you are using in your list a Map object with primitive types, you can use jsonEncode and convert to a String that can be saved in sharedPreferences and use jsonDecoder when want to revert.
like this:
String toBeSaved = jsonEncode(savedData);
prefs.setString('dataTest', toBeSaved);
Try using jsonEncode and jsonDecode from import 'dart:convert';
Like so:
Future<void> saveDataTest() async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString("dataTest ", jsonEncode(savedData));
}
Future<String> getDataStringTest() async {
final prefs = await SharedPreferences.getInstance();
savedData = List.from(jsonDecode(prefs.getString("dataTest")));
setState(() {});
}

type 'String?' can't be assigned to type 'String'

Here's my code
Saving String to shared preference
if (croppedFile != null) {
imageFile = croppedFile;
final bytes = Io.File(imageFile!.path).readAsBytesSync();
String img64 = base64Encode(bytes);
setState(() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('image', img64);
});
}
Calling shared preference
SharedPreferences prefs = await SharedPreferences.getInstance();
var iMG = prefs.getString('image');
await DatabaseHelper.instance.add(
Cards(
name: NamaKartuController.text,
desc: DescKartuController.text,
iMG : iMG
)
);
i set it as a String but it does still giving -
The argument type 'String?' can't be assigned to the parameter type 'String
Error
I think error is in this line. Try to convert this line into string as below-
String img64 = base64Encode(bytes).toString();
Please let me know the errr again?
base64Encode(bytes) Can return null meaning it has a return type of String?, and not String.
Because String img64 isn't declared as a nullable variable, it will not accept a value of null. You can change the method call to base64Encode(bytes)!, which will assert if the returned value of base64Encode(bytes)! is null at runtime.
Simply adding .toString() to the existing code doesn't really deal with the issue, as if null is returned from the method, it'll just convert that to the string "null", which feels more like just getting the code to fail silently instead of fixing the issue.
https://dart.dev/codelabs/null-safety

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

Access to SharedPreferences method via class

I've a separate file which includes a class with a function:
getstatus.dart
class GetStatus {
isActive() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
bool boolValue = prefs.getBool('notification') ?? false;
return boolValue;
}
}
To access the function: final bool getStatus = GetStatus().isActive();. However Flutter gives me the error type 'Future<dynamic>' is not a subtype of type 'bool'. Probably the isActive() method is wrong but what exactly should I change? Btw: the return value must be a bool.
Change the signature to:
Future<bool> isActive() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
return prefs.getBool('notification') ?? false;
}
To consume this, you need to:
fecthActive() async {
var activeValue = await getStatusInstance.isActive();
//do something else...
}
Now you can use activeValue as a bool.
To deal with Futures in Dart, goto this doc: https://dart.dev/codelabs/async-await

Flutter: how to get value from sharedpreferences? when i debug, the value is Instance of 'Future<String>'

i entered data using
Future<bool> saveSession() async{
final SharedPreferences pref = await SharedPreferences.getInstance();
return pref.setString('test', 'Some Data');
}
and get data using
Future<String> readSession() async{
final SharedPreferences pref = await SharedPreferences.getInstance();
return pref.getString('test');
}
when i try to debug it using
print(readSession()); // value is Instance of 'Future'
i dont know why ??
result is Instance of 'Future'
To get the string value you need to resolve the Future object first. There are basically two ways to achieve that:
1
print(await readSession());
2
readSession().then((v) => print(v));
You can read more about asynchronous operations in official docs - https://dart.dev/tutorials/language/futures