I am coding a relatively simple app where one can set an emergency contact and in case of emergency, a text is sent to the contact by the touch of a remote button (connected via Bluetooth.) I have used the package contact picker and it works perfectly. Now, the issue is that I'm trying to save the contact locally for when the app is relaunched. The set state line returns an error that I cannot set contact to type string.
final ContactPicker _contactPicker = new ContactPicker();
Contact _contact;
#override
void initState() {
getData();
}
getData() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
_contact = prefs.getString(_contact.toString());
});
}```
maybe u need to decode that string from prefs so that it can get converted in Contact instance.
this line prefs.getString(_contact.toString()) is returning string in $fullName: $phoneNumber this format
e.g.
var decodedList = prefs.getString('contact').split(" ");
setState(() {
_contact = Contact(fullName: decodedList.first, phoneNumber: decodedList[1]);
});
Related
In my code at the home page fetch user name from firestore database and that's display nicely in UI. I want pass that name to shared preference function and store there and use that name in another pages also.
Code
home page code ( initstate and send name to saveNameToSharedPreferences() method )
#override
void initState() {
super.initState();
getData();
fetchName();
storeName();
}
void storeName() {
String displayName = '${user?.displayName}';
return displayName.saveNameToSharedPreferences();
}
SharedPreferences code
import 'package:shared_preferences/shared_preferences.dart';
String? _displayName;
String? get displayName => _displayName;
Future saveNameToSharedPreferences() async {
final SharedPreferences sn = await SharedPreferences.getInstance();
await sn.setString('displayName', _displayName!);
}
Future getNameFromSharedPreferences() async {
final SharedPreferences sn = await SharedPreferences.getInstance();
_displayName = sn.getString('displayName');
}
How to solve this ?
You are calling function as an extension. Try to pass parameter instead.
Make the following changes
Future saveNameToSharedPreferences(String displayName) async {
final SharedPreferences sn = await SharedPreferences.getInstance();
await sn.setString('displayName', displayName);
}
And call it as
void storeName() {
String displayName = '${user?.displayName}';
saveNameToSharedPreferences(displayName);
}
I am having trouble identifying as to why setState() is returning null on my shared preferences getString method.
I am calling an async function outside of the initState and the constantly printing null when i check the return string of getString on page load.
I have checked that setString is saving the correct string to the key.
Here is my code:
void initState() {
super.initState();
retrieve();
}
retrieve() async {
final prefs = await SharedPreferences.getInstance();
setState(() {
name = prefs.getString("displayName");
print(name);
});
}
Here is where I setString(in the register user page):
try {
UserCredential result =
await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: _emailController.text,
password: _passwordController.text,
);
final user = FirebaseAuth.instance.currentUser;
final name = _usernameController.text;
// if (user != null) {
await user?.updateDisplayName(name);
Navigator.pushNamed(context, homeRoute);
print(name);
You should set ,username via shared preference before accessing it.
final prefs = await SharedPreferences.getInstance();
In register page.(where you want to set name via SharedPreference before accessing it)
await prefs.setString('displayName', 'name');
After setting it in registeration you can access like above
name = prefs.getString("displayName");
When SharedPreferences return null value it means you have not set value with your key yet. So firstly set something like this:
final prefs = await SharedPreferences.getInstance().reload();
await prefs.setString('displayName', 'Mark');
then try to call it.
Thanks to all who have spent the time to respond to help. I hope this answer might help some one else down the track.
I found that Shared Preferences was not saving the data - my code was fine after all. I simply just closed the app and restarted the X code build from scratch and it is now working.....
I am coding a to-do list app in flutter but every time I close the app, all my to-do's are gone, and none of them are stored. How do I stop them from disappearing every time I close the app?
Use sqlite or files. Please refer documentation on cookbooks for either approach.
https://docs.flutter.dev/cookbook/persistence
Your other option is to use an external database over the internet
To persist your data (todo list) you can either
store data on the users device
You can do this by using a local databases like sqflite, sqfentity, shared_preferences etc
or store the data on the server
Using this option you can either spin up your own server or use some quick serverless solutions like supabase or cloud firestore from firebase.
I recommend hive it’s very easy to use and it’s lightweigh.
In addition with all the other propositions, you can try Isar, which is a NoSQL local database that can be used for all platforms:
https://isar.dev/tutorials/quickstart.html
https://pub.dev/packages/isar
Apps generally store data in temporary storage which destroyed every time yo close the app. in order to save data permanently, you could use sqflite database or shared_preferences database
if you want use shared_preferences, you can do this:
first make class that call StorageManager:
import 'package:shared_preferences/shared_preferences.dart';
class StorageManager {
static Future<bool> saveData(String key, dynamic value) async {
final prefs = await SharedPreferences.getInstance();
await prefs.reload();
if (value is int) {
prefs.setInt(key, value);
return true;
} else if (value is String) {
prefs.setString(key, value);
return true;
} else if (value is bool) {
prefs.setBool(key, value);
return true;
} else {
return false;
}
}
static Future<dynamic> readData(String key) async {
final prefs = await SharedPreferences.getInstance();
await prefs.reload();
dynamic obj = prefs.get(key);
return obj;
}
static Future<bool> deleteData(String key) async {
final prefs = await SharedPreferences.getInstance();
return prefs.remove(key);
}
static Future<void> reloadSharedPreferences() async {
final prefs = await SharedPreferences.getInstance();
await prefs.reload();
}
}
then use it like this:
when you want save some thing in storage call this:
await StorageManager.saveData('some unique key', your int or string or bool value);
when you want read from storage:
var result = await StorageManager.readData('some unique key');
if (result != null) {
// use your value
} else {
// this means there is no result
}
I have a piece of code trying to initialize the fields with data from two different users in the firebase realtime database, I tried various ways but all of them don't work and the field is not initialized error keeps popping up.
Here is the code:
class _PartnerProfilePageState extends State<PartnerProfilePage> {
final userUID = FirebaseAuth.instance.currentUser!.uid;
final database = FirebaseDatabase.instance.ref();
late final partnerUID;
late final profilePath;
late final partnerName;
late final birthday;
late final en;
#override
initState() {
super.initState();
initInfo();
}
initInfo() async {
database.child(userUID).onValue.listen((event) {
final data = Map<dynamic, dynamic>.from(event.snapshot.value as Map);
setState(() {
partnerUID = data['partner'];
en = data['language'].toString().startsWith('en');
initPartnerInfo();
});
});
}
Future initPartnerInfo() async {
final ppsnapshot =
await database.child(partnerUID).child('profilePath').get();
profilePath = ppsnapshot.value.toString();
final nsnapshot = await database.child(partnerUID).child('username').get();
partnerName = nsnapshot.value.toString();
final bsnapshot = await database.child(partnerUID).child('birtday').get();
birthday = bsnapshot.value.toString();
}
//rest of other unrelated stuff like build down there
}
(My firebase realtime database has no 'user' branch but directly save every user in the root with their userid).
I think there is a problem with the async initializing. The build method can try to build before you initialize the last variable(Because initState method can not async). You can easily check my theory.Delete the 'method call'(the initInfo) inside the initState(). Just create a button in the screen, give it a anonymous async function, inside the function call your init method and try to call your variables like this:
() async{
await initInfo();
print('partnerUID');
}
Easy way to checking out initialization process. Hope it helps.
So I'm in this course by London App Brewery. I'm making weather app, and a problem appears when function needs to update my UI with relevant weather data. I've done everything like tutor from the course, but it looks like something is changed since they made that app.
The function looks like this:
WeatherModel weather = WeatherModel();
int temperature;
String weatherIcon;
String weatherText;
String cityName;
#override
void initState() {
super.initState();
updateUI(widget.locationWeather);
}
void updateUI(dynamic weatherData) {
setState(() {
double temp = weatherData["main"]["temp"] - 273.15;
temperature = temp.toInt();
int condition = weatherData["weather"][0]["id"];
weatherIcon = weather.getWeatherIcon(condition);
cityName = weatherData["name"];
weatherText = weather.getMessage(temperature);
});
This is exactly the code from the course which should work, but it doesn't for me. Error appears saying it expects a future (updateUI function). So I did some research and updated the function like this:
void updateUI(Future<dynamic> locationWeather) async{
var weatherData = await locationWeather;
setState(() {
double temp = weatherData["main"]["temp"] - 273.15;
temperature = temp.toInt();
int condition = weatherData["weather"][0]["id"];
weatherIcon = weather.getWeatherIcon(condition);
cityName = weatherData["name"];
weatherText = weather.getMessage(temperature);
});
So like this I get it kinda working. Main screen where this data is shown, works. But a screen before that one, its where actual API call happens and it uses navigator to switch to main screen. It also shows loading spinner, while it gets data. So situation is, my loading screen is showing error about Text widgets being null and it switches to main screen where everything works as it should. I guess that because values in those text widgets are actually null since this function is called on main screen initState and not on loading screen.
EDIT:
locationWeather comes from Loading Screen class:
class _LoadingScreenState extends State<LoadingScreen> {
double latitude;
double longitude;
#override
void initState() {
super.initState();
getLocationData();
}
void getLocationData() async {
Location location = Location();
await location.getCurrentLocation();
NetworkHelper networkHelper = NetworkHelper(
"https://api.openweathermap.org/data/2.5/weather?
lat=${location.latitude}&lon=${location.longitude}&appid=$apiKey");
var weatherData = networkHelper.getData();
Navigator.push(context, MaterialPageRoute(builder: (context) {
return LocationScreen(weatherData); // this is locationWeather
}));
}
The issue is you are passing a Future instead of actual data. The getData method returns a future, you need to await for the result.
var weatherData = await networkHelper.getData();