I am creating an Flutter application in which i need to store the user information and for some extent i am able to achieve it with Shared Prefrence.
i am storing the data at login screen as follows:
var displayName=jsondata["username"];
SharedPreferences prefs=await SharedPreferences.getInstance();
prefs.setString('displayName', displayName);
and on my drawerScreen i am getting the same data as follows:
late String displayName;
initState() {
getData();
super.initState();
}
getData() async{
SharedPreferences prefs = await SharedPreferences.getInstance();
displayName=prefs.getString('displayName')!;
}
but whenever i click on drawer button there is an error as shown:
LateInitializationError: Field 'displayName' has not been initialized.
but when i hot reload my app while drawer is opened there is no error when i go to other screen and get back to drawer the LateInitialization errro arises,
i dont know what causing this error
and this is the other screen where i am shifting from drawer:
late String displayName;
getData() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
displayName=prefs.getString('displayName')!;
print(displayName);
}
initState() {
getData();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).backgroundColor,
key: _scaffoldKey,
drawer: SizedBox(
width: MediaQuery.of(context).size.width * 0.75 < 400 ?
MediaQuery.of(context).size.width * 0.75 : 350,
child: Drawer(
child: AppDrawer(
selectItemName: 'Home',
),
),
),
appBar: AppBar(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
automaticallyImplyLeading: false,
title: Row(
children: <Widget>[
SizedBox(
height: AppBar().preferredSize.height,
width: AppBar().preferredSize.height 40,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
alignment: Alignment.centerLeft,
child: GestureDetector(
onTap: () {
_scaffoldKey.currentState!.openDrawer();
},
child: Icon(
Icons.dehaze,
color: Theme.of(context).textTheme.headline6!.color,
),
),
),
),
),
],
),
),
can someone suggest me a better way of doing it . Thanks in advance <3
CodePudding user response:
Your problem is that initState
is not async
(and it can't be async
), so your getData
will likely (or surely) be completed later than the build
method is called. Since you set displayName
in getData
, and you marked it as late
, you will get this error. That's why it is working after hot reload, because at that time displayName
is already initalized.
One possible solution is to call SharedPreferences.getInstance()
(this is why your getData
needs to be async
) somewhere earlier in your application, for example in main() async
function, store the result of getInstance
using a ChangeNotifierProvider
(or any other way that allows you to use this value in this widget), and use its value in getData
. This way getData
does not need to be async
, and displayName
will be initalized before build
method is called. This can be useful if you use SharedPreferences
in more than one place, because you don't have to await
the result of getInstance
each time.
Another approach is not declaring displayName
as late
, but allow it to be null
, and then in the build
method you can use a FutureBuilder
which completes upon getData
is executed, and the building of Scaffold
will only be started after this future completes. In this case you can display a progress indicator while the future is not completed.
CodePudding user response:
I forgot to to add setState();
late String displayName;
initState() {
getData();
super.initState();
}
Future getData() async{
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
displayName=prefs.getString('displayName')!;
});
}