I am trying to save the notification title and body using shared preference but i am unable to - flutter

#I am trying to save the notification title and body locally and fetch the title and body inside my app to show all the sent notification in a listview but i am unable to
#this is the code i am running this code in my main.dart inside initstate and that detail.add is my list which i created manually but i am getting error saying 102:45: Error: This expression has type 'void' and can't be used.prefs.setString('notificationData', setData); when i try to setString this is the error i get
List<String?> detail = [];
FirebaseMessaging.onMessage.listen((message) async{
if(message.notification!=null){
// print(message.notification!.body);
// print(message.notification!.title);
final title = message.notification?.title;
final body = message.notification?.body;
SharedPreferences prefs = await SharedPreferences.getInstance();
final String notificationData = json.encode({"title":title,"body":body});
final setData = detail.add(notificationData);
prefs.setString('notificationData', setData);
print(notificationData);
print(setData);
}

The detail.add(notificationData) function returns nothing (void) and only adds to the existing array, so your setData variable is empty but you can use the original updated detail array like so:
FirebaseMessaging.onMessage.listen((message) async{
if(message.notification!=null){
// print(message.notification!.body);
// print(message.notification!.title);
final title = message.notification?.title;
final body = message.notification?.body;
SharedPreferences prefs = await SharedPreferences.getInstance();
final String notificationData = json.encode({"title":title,"body":body});
detail.add(notificationData);
prefs.setString('notificationData', detail.toString());
print(notificationData);
print(detail);
}
//...
});

Related

How to store field value from firestore in Flutter?

For example, in the image below, I would like to store the value "hi" in a string in Flutter from Firestore. However, when I print the value, I keep getting Instance of 'Future<dynamic>'
Any idea how to do this?
Edit: One thing I am trying to do is basically get the data and see if its equal to a specific value. For example, if the field text is equal to "hello", then I would print "hi" to the screen
Code:
final firestoreInstance = FirebaseFirestore.instance;
final FirebaseAuth auth = FirebaseAuth.instance;
Future<String> getString(docID) async {
String? roleValue = '';
DocumentSnapshot docSnapshot = await firestoreInstance
.collection('messages')
.doc(docID)
.get();
roleValue = docSnapshot.data()!['text'];
return roleValue;
}
Seems like you are not awaiting the call as this is an async function.
You have to add await just before calling the getString function.
final result = await getString('abc);
print(result);
Now the result will no more Instance of 'Future<dynamic>'

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

How can i save shared prefrence in list?

i have two class , in first class set sharedPrefrence like this :
[{"name":"alex","code":"12345"}]
my shared prefrence set method :
Future _shared() async {
final _customer = {
"name": _controller1.text,
"code": _controller2.text,
};
List<Map<String, dynamic>> customers = [];
customers.add(_customer);
final customerEncode = jsonEncode(customers);
SharedPreferences pref = await SharedPreferences.getInstance();
pref.setString("list_customer", customerEncode);
print(customerEncode);
}
and show this list in second class , i want when back to first class and enter name and code , they are add to previous list(keep later data) like this :
[{"name":"alex","code":"12345"},{"name":"john","code":"98765"}]
how can i do this ?
Create Customer Model:
class Customer{
Customer({this.name, this.code});
String name;
String code;
Customer.fromMap(json)
: name = json['name'].toString(),
code= json['code'].toString();
}
Then, create a method which adds into your SharedPreferences list:
addIntoList(Customer obj){
List<Customer> customersList = new List();
SharedPreferences pref = await SharedPreferences.getInstance();
// get list from SharedPreferences
var customers = pref.getString("list_customer");
var customersDecode = jsonDecode(customers);
// loop through your saved array and get them into customersList
customerDecode.forEach((val) {
customersList.add(Customer.fromMap(val));
});
// at last, add your parameter object
customersList.add(obj);
// save list to SharedPreferences
pref.setString("list_customer", jsonEncode(customersList));
}

List.map returns List<Future>

I got a class for handling SharePreferences
class SharedPreferencesUtils {
static Future<String> getSharedPreference(String key) async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
return prefs.getString(key);
}
}
I try to use this class from another class to get all my sharedPreferences with this method:
void getAllPrefs() async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
var keyList = prefs.getKeys().toList();
var valueList = keyList.map((key) async {
String value = await SharedPreferencesUtils.getSharedPreference(key);
return value;
}).toList();
print("KEY LIST IS $keyList");
print("VALUE LIST IS $valueList");
}
And, while the keyList works well, the valueList just returns:
VALUE LIST IS [Instance of 'Future<String>', Instance of 'Future<String>', Instance of 'Future<String>', Instance of 'Future<String>', Instance of 'Future<String>', Instance of 'Future<String>', Instance of 'Future<String>', Instance of 'Future<String>', Instance of 'Future<String>', Instance of 'Future<String>']
I don't really get why I am not getting the actual String value corresponding to the key, as I understood Futures, in this case, the execution should await until the var value gets the String value that I am asking for.....am I wrong?
Note: there are values stored in SharedPreferences, that is for sure.
This is a good one :)
I will only need to mention one key concept and you will see why this is happening: Any async function returns a Future.
In your case, the map call uses an async callback and hence the values in your lists are Futures.
There is a helper in the Future class: Future.wait
You can simply pass your Iterable to it and it will return a list with resolved futures:
Future<void> getAllPrefs() async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
final keyList = prefs.getKeys().toList();
final valueList = await Future.wait(keyList.map((key) async {
String value = await SharedPreferencesUtils.getSharedPreference(key);
return value;
}));
print("KEY LIST IS $keyList");
print("VALUE LIST IS $valueList");
}
How do you do it without the helper? Well, not use map because it requires a callback, but you need to stay in the same scope if you want to get rid of Future values as any outside function would need to be async. So here you go:
Future<void> getAllPrefs() async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
final keyList = prefs.getKeys().toList();
final valueList = List<String>(keyList.length);
for (int i = 0; i < valueList.length; i++)
valueList[i] = await SharedPreferencesUtils.getSharedPreference(keyList[i]);
print("KEY LIST IS $keyList");
print("VALUE LIST IS $valueList");
}
One practice that helps you to remember that all async functions return futures is using Future<void> as the return type instead.
If you use Future.wait, i.e. still use your map call, you can make it a lot more concise like this:
await Future.wait(keyList.map(SharedPreferencesUtils.getSharedPreferences));
You can just use keyList.map(SharedPreferencesUtils.getSharedPreferences) because getSharedPreferences already takes a String and returns a Future<String>, which is equivalent to what you were doing before :)

Instance of 'Future<String>' instead of showing the value

Iam using flutter and I am trying to get a value from shared_preferences that I had set before, and display it in a text widget. but i get Instance of Future<String> instead of the value. here is my code:
Future<String> getPhone() async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
final String patientPhone = prefs.getString('patientPhone').toString();
print(patientPhone);
return patientPhone;
}
Future<String> phoneOfPatient = getPhone();
Center(child: Text('${phoneOfPatient}'),))
There is await missing before prefs.getString( and use setState() instead of returning the value. build() can't use await.
String _patientPhone;
Future<void> getPhone() async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
final String patientPhone = await /*added */ prefs.getString('patientPhone');
print(patientPhone);
setState(() => _patientPhone = patientPhone);
}
build() {
...
Center(child: _patientPhone != null ? Text('${_patientPhone}') : Container(),))
}
If you don't have the option to use await or async you can do the following.
getPhone().then((value){
print(value);
});
and then assign a variable to them. From that, you'll have the result from the value.