I wanna ask how to save state from textfield? cause i can't saving this state, after hot restart my value always reset, i just want to save state after hot restart, can i know my problem where it's wrong?
it's my code:
class HomePage extends StatefulWidget {
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
TextEditingController nameController = TextEditingController();
var nama = 'nama';
void setPref() async {
var prefs = await SharedPreferences.getInstance();
prefs.setString(nama, nameController.text);
}
void load() async {
var prefs = await SharedPreferences.getInstance();
setState(() {
nama = prefs.getString(nameController.text) ?? '';
nameController.text = nama;
});
}
#override
void initState() {
// TODO: implement initState
super.initState();
load();
}
#override
Widget build(BuildContext context) {
.....
}
}
There is a problem in your code:
In shared Prefrences you have to use key to store and get value.
But you are using it in wrong way:
Here is correct code:
void load() async {
var prefs = await SharedPreferences.getInstance();
String value = '';
setState(() {
value= prefs.getString(nama) ?? '';
nameController.text = value;
});
}
The nama is a key name and you are also using it to receive value. And the key you are using is nameController.text is also wrong.
Bonus
The convection of writing keys in Flutter is Following:
String nameKey = 'NAMEKEY';
Related
Can someone explain to me where I am wrong? I am programming this application and, working with sqflite, I have had this kind of problem several times when I use the readPlayer() function.
class matchesRow extends StatefulWidget {
final List matches;
final List results;
final int index;
matchesRow({
Key? key,
required this.index,
required this.matches,
required this.results,
}) : super(key: key);
#override
State<matchesRow> createState() => _matchesRowState();
}
class _matchesRowState extends State<matchesRow> {
late Player gP1;
late Player gP2;
bool ripescato = false;
PlayersDatabase pb = PlayersDatabase.instance;
#override
void initState() {
super.initState();
getPlayers();
}
#override
void dispose() {
PlayersDatabase.instance.close();
super.dispose();
}
Future getPlayers() async {
List<dynamic> duel = widget.matches[widget.index];
gP1 = await pb.readPlayer(duel[0]);
print(gP1);
gP2 = await pb.readPlayer(duel[0]);
if (duel[1] == "R") {
ripescato = true;
} else {
gP2 = await pb.readPlayer(duel[1]);
}
}
#override
Container build(BuildContext context) {
var icon = Icons.code_sharp;
return Container(child: Text(gP1.name));
}}
This is the function ReadPlayer()
Future<Player> readPlayer(int id) async {
final db = await instance.database;
final maps = await db.query(
tablePlayers,
columns: PlayerFields.values,
where: '${PlayerFields.id} = ?',
whereArgs: [id],
);
if (maps.isNotEmpty) {
return Player.fromJson(maps.first);
} else {
throw Exception('ID $id not found');
}
I don't understand why even if I declare the value of gP1 and gP2 in getPlayers() the error still pop up.
gP1 and gP2 getting from future method. It will take some time to fetch data from future method getPlayers. Use FutureBuilder or make it nullable
For nullable case it will be
Player? gP1;
Player? gP2;
#override
void initState() {
super.initState();
getPlayers().then((value) {
//update Ui after getting data
setState(() {});
});
}
And use case with default value on null case
Text(gP1?.name??"didnt get yet")
I want to save a variable's value that changes every 5 seconds then read it. I have already tried saving it to shared preferences then reading it but the problem with that was that the value was only saved one time and did not save the changes done to the variable. Is there a way to implement that in flutter?
class _MyAppState extends State<MyApp> {
void initState() {
super.initState();
Future.delayed(Duration.zero, () {
_connect();
});
}
...
void predict(List<double> v) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
List<List<double>> L=List<List<double>>.filled(1, [0], growable: true);
L[0]=v;
...
String res=response.body;
Map R = json.decode(res);
var _list = R.values.toList();
print(res);
Proba= double.parse(_list[1]);
await prefs.setDouble('Proba', Proba);
}
....
class Page extends StatefulWidget {
Page({Key key, this.title}) : super(key: key);
final String title;
#override
PageState createState() => PageState();
}
class PageState extends State<Page> {
.....
Future<double> _getProbaFromSharedPref() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
return prefs.getDouble("Proba") ?? 0;
}
#override
void initState() {
super.initState();
Location1=_getCurrentLocation();
_getStringFromSharedPref();
_getProbaFromSharedPref().then((s) {
Value = s;
});
Future.delayed(Duration.zero, () {
_check();
});
}
}
In the code I tried saving the variable in sharedPreferences then reading it, but I have no clue on how to reload it everytime it changes.
I pass the value of both userProfileID And ,userstype to Profilepage() as shown below but when i go to profile page and I try to print the value of both this variable I will get Null value, I think they Actually not passed from this _HomePageState, anyone help?
Here is Where I pass the Value of both
userProfileID as a UserID and userstype as UserTypes inside initState() below,
and both UserID and UserTypes are Obtained from SharedPrefrence
(I call GetData to obtain the value of UserID and UserTypes from SharedPreference )
class _HomePageState extends State<HomePage> {
String UserID;
String UserTypes;
List<Widget>_children;
bool isSignedIn= false;
int _CurrentIndex=0;
void initState(){
super.initState();
GetData();
_children=[
TimeLinePage(UsersIdTimeline:UserID,UsersTypeTimeline:UserTypes),
SearchPage(searchUserSID: UserID,searchUsertype:UserTypes), //search(),
UploadPage(uploadUserSID:UserID,uploadUsertype: UserTypes),
NotificationsPage(NotifyUserSID: UserID,NotifyUsertype:UserTypes),
ProfilePage(userProfileID:UserID,userstype:UserTypes),
];
if(FirebaseAuth.instance.currentUser!=null){
setState(() {
isSignedIn= true;
});
}else{
setState(() {
isSignedIn= false;
});
}
}
#override
Widget build(BuildContext context) {
if(isSignedIn){
return buildHomeScreen();
} else{
return buildSignedInScreen();
}
}
void GetData()async {
SharedPreferences preferences= await SharedPreferences.getInstance();
setState(() {
UserID=preferences.get('UserId');
UserTypes=preferences.get('UserType');
});
}
}
here is buildHomeScreen
class _HomePageState extends State<HomePage> {
// ignore: non_constant_identifier_names
String UserID;
String UserTypes;
List<Widget>_children;
List<Widget>_agentchildren;
bool isSignedIn= false;
// ignore: non_constant_identifier_names
int _CurrentIndex=0;
int _agentCurrentIndex=0;
void initState(){
super.initState();
GetData();
_children=[
TimeLinePage(UsersIdTimeline:UserID,UsersTypeTimeline:UserTypes),
SearchPage(searchUserSID: UserID,searchUsertype:UserTypes),
UploadPage(uploadUserSID:UserID,uploadUsertype:UserTypes),
NotificationsPage(NotifyUserSID: UserID,NotifyUsertype:UserTypes),
ProfilePage(userProfileID:UserID,userstype:UserTypes),
];
if(FirebaseAuth.instance.currentUser!=null){
setState(() {
isSignedIn= true;
});
}else{
setState(() {
isSignedIn= false;
});
}
}
#override
Widget build(BuildContext context) {
if(isSignedIn){
if(UserTypes=='agent'){
return buildagentScreen();
} else if(UserTypes== 'Signupuser'||
UserTypes== 'owner'||
UserTypes== 'seller'
){
return buildHomeScreen();
}else{
return buildSignedInScreen();
}
}
}
Here is My ProfilePage(), if I try to get the value of both
( String userstype; String userProfileID;) in this page
i get Null value but I alredy pass the value of them from the above _HomePageState()
class ProfilePage extends StatefulWidget {
String userstype;
String userProfileID;
ProfilePage({this.userProfileID, this.userstype});
#override
_ProfilePageState createState() => _ProfilePageState();
}
class _ProfilePageState extends State<ProfilePage> {
final String CurrentOnlineUserID=curentuser?.uid;
bool loading =false;
int countPost=0;
String postOrientation="grid";
List<Post> PostList=[];
void initState(){
getAllProfilePost();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
appBar:header(context,strTitle:"profile"),
body:ListView(
children:<Widget>[
TopView(),
]
),
);
}
Use shared preferences globally for your application.
import 'dart:async' show Future;
import 'package:shared_preferences/shared_preferences.dart';
class PreferenceUtils {
static Future<SharedPreferences> get _instance async => _prefsInstance ??= await SharedPreferences.getInstance();
static SharedPreferences _prefsInstance;
// call this method from iniState() function of mainApp().
static Future<SharedPreferences> init() async {
_prefsInstance = await _instance;
return _prefsInstance;
}
static String getString(String key, [String defValue]) {
return _prefsInstance.getString(key) ?? defValue ?? "";
}
static Future<bool> setString(String key, String value) async {
var prefs = await _instance;
return prefs?.setString(key, value) ?? Future.value(false);
}
}
Please follow this link
https://stackoverflow.com/a/61046061/8218866
When the _HomePageState is created, the initState is called, and so this line:
_children=[
[...],
ProfilePage(userProfileID:UserID,userstype:UserTypes),
];
This line is creating the object of a ProfilePage with the desired UserID's and UserTypes. This ProfilePage object will be put inside the _children list.
When you do this:
setState(() {
UserID=preferences.get('UserId');
UserTypes=preferences.get('UserType');
});
You are 1) calling the build method again, and 2) updating the value of UserID and UserTypes. You did not change the value of any itens inside the _childrens list. Or the list itself. Hence the misbehavior you noticed.
There are many ways to solve this, but the essence would be to move this list declaration inside the build method. An example:
#override
Widget build(BuildContext context) {
_children = [.....]
if(isSignedIn){
[...]
Doing this way would not be a pretty way to do it, because you are creating lots of new (and useless) objets every time the build method is called. Maybe in a small application this wouldn't be a problem, and for didactic reasons I chose to show this way in this answer.
The more correct way would be to :
Switch and instantiate inside buildHomeScreen the body object:
Scaffold buildHomeScreen(){
Widget body;
switch (_currentIndex) {
case 0:
body =
TimeLinePage(UsersIdTimeline:UserID,UsersTypeTimeline:UserTypes);
break;
case 1:
body = ...;
break;
}
return Scaffold(
...
body: body,
...
)
}
Which should give you the same result.
The following code is part of my login screen. I am using shared_preferences to save the remember me checkbox and the user name. The checkbox value is working, but the user name is not being set. I know it is being saved because I can see the value using print. But I guess it is being set too late, as my TextField is blank. Any ideas?
class RmoLogin extends StatefulWidget {
static const String id = 'login_screen';
#override
_RmoLoginState createState() => _RmoLoginState();
}
class _RmoLoginState extends State<RmoLogin> {
final TextStyle style = TextStyle(fontFamily: 'Montserrat', fontSize: 20.0);
final TextEditingController usernameController = TextEditingController();
final TextEditingController passwordController = TextEditingController();
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
bool showSpinner = false;
bool rememberMe = false;
String userName = '';
_saveRememberUser() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('username', usernameController.text);
prefs.setBool('remember', rememberMe);
}
_getRememberUser() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
userName = prefs.getString('username') ?? '';
rememberMe = prefs.getBool('remember') ?? false;
}
#override
void initState() {
super.initState();
_getRememberUser();
if (rememberMe) {
usernameController.text = userName;
}
}
#override
Widget build(BuildContext context) {
final userField = UserTextField(style: style, usernameController: usernameController);
final passwordField = PasswordTextField(style: style, passwordController: passwordController);
final rememberMeCheckbox = Checkbox(
value: rememberMe,
onChanged: (newValue) {
setState(() {
rememberMe = newValue;
});
},
);
Because the SharedPreferences instantiation is asynchronous and the build method itself is not, by the time the instance is created and the value is accessed, the build method would have already been called and your widgets built.
However, For things like SharedPreferences and databases, the best way to implement them is to use the Singleton approach, i.e, one instance that you can use across the entire application.
In this case instead of creating a new SharedPreferences instance whenever either method is called, it will be best to create a single instance of it and use that instance to update the set and get the values.
You could also create a service for the SharedPreferences which you could use across the entire application.
class SharedPreferencesService {
final SharedPreferences _prefs;
SharedPreferencesService(this._prefs);
// define methods here
}
Then in your main method, you can create an instance of SharedPreferences and use it to initialize the SharedPreferencesService.
eg.
SharedPreferencesService service;
Future<void> main() async {
// flutter will complain if this isn't present
WidgetsFlutterBinding.ensureInitialized();
final prefs = await SharedPreferences.getInstance();
service = SharedPreferencesService(prefs);
runApp(YourApp());
}
Then wherever you want to use it in your app, you can call the method name on the service. It is best to use Dependency Injection for the SharedPreferencesService though, you can try the get_it library.
Just a brief look.... but
You are calling _getRememberUser synchronously within initState() when it is an async method
initState() isn't the correct place to be calling it as initState() itself is a synchronus #override.
My solution would be to use a FutureBuilder in your build() method, and call _getRememberUser there.
You just need to update the state that's it check the below solution:
bool rememberMe = false;
String userName = '';
#override
void initState() {
// TODO: implement initState
super.initState();
_getRememberUser();
}
_getRememberUser() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
userName = prefs.getString('username') ?? '';
rememberMe = prefs.getBool('remember')?? false;
});
if (rememberMe) {
usernameController.text = userName;
}
print(userName +'-->'+rememberMe.toString());
}
Happy Coding!!
I use method, that I call from InitState() where load SP with await.
But Widget is constructing before SP is loaded and have got empty SP values.
void getSP() async {
var prefs = await SharedPreferences.getInstance();
_todoItems = prefs.getStringList("key") ?? _todoItems;
}
Full code: https://pastebin.com/EnxfKgPH
there are many options, one i like is to use boolean variable like this
bool isLoaded = false;
#override
void initState() {
getSP();
super.initState();
}
void getSP() async {
var prefs = await SharedPreferences.getInstance();
_todoItems = prefs.getStringList("key") ?? _todoItems;
setState(() => isLoaded = true);
}
then check it to determine if build tree should load or not, like this..
#override
Widget build(BuildContext context) {
return !isLoaded ? CircularProgressIndicator() : Scaffold(...);
}