LateInitializationError: Field 'displayName' has not been initialized in Flutter's Shared Prefrence?
LateInitializationError: Field 'displayName' has not been initialized in Flutter's Shared Prefrence?
我正在创建一个 Flutter 应用程序,我需要在其中存储用户信息,并且在某种程度上我可以通过共享首选项来实现它。
我在登录屏幕上存储的数据如下:
var displayName=jsondata["username"];
SharedPreferences prefs=await SharedPreferences.getInstance();
prefs.setString('displayName', displayName);
在我的 drawerScreen 上,我得到了如下相同的数据:
late String displayName;
initState() {
getData();
super.initState();
}
getData() async{
SharedPreferences prefs = await SharedPreferences.getInstance();
displayName=prefs.getString('displayName')!;
}
但是每当我点击抽屉按钮时都会出现错误,如图所示:
LateInitializationError: Field 'displayName' has not been initialized.
但是当我在抽屉打开时热重载我的应用程序时没有错误当我转到其他屏幕并返回抽屉时出现 LateInitialization 错误,
我不知道是什么导致了这个错误
这是我从抽屉移出的另一个屏幕:
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,
),
),
),
),
),
],
),
),
有人可以建议我更好的方法吗。提前致谢 <3
你的问题是 initState
不是 async
(也不可能是 async
),所以你的 getData
很可能(或肯定)完成晚于调用 build
方法。由于您在 getData
中设置了 displayName
,并将其标记为 late
,因此您会收到此错误。这就是它在热重载后工作的原因,因为那时 displayName
已经初始化。
一个可能的解决方案是在您的应用程序中较早的某个地方调用 SharedPreferences.getInstance()
(这就是为什么您的 getData
需要 async
),例如在 main() async
函数中,使用 ChangeNotifierProvider
(或允许您在此小部件中使用此值的任何其他方式)存储 getInstance
的结果,并在 getData
中使用其值。这样 getData
不需要是 async
,并且 displayName
会在调用 build
方法之前初始化。如果您在多个地方使用 SharedPreferences
,这会很有用,因为您不必每次都 await
getInstance
的结果。
另一种方法是不将 displayName
声明为 late
,而是允许它是 null
,然后在 build
方法中您可以使用 FutureBuilder
在 getData
执行后完成,而 Scaffold
的构建只会在这个未来完成后开始。在这种情况下,您可以在未来未完成时显示进度指示器。
我忘了添加 setState();
late String displayName;
initState() {
getData();
super.initState();
}
Future getData() async{
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
displayName=prefs.getString('displayName')!;
});
}
我正在创建一个 Flutter 应用程序,我需要在其中存储用户信息,并且在某种程度上我可以通过共享首选项来实现它。
我在登录屏幕上存储的数据如下:
var displayName=jsondata["username"];
SharedPreferences prefs=await SharedPreferences.getInstance();
prefs.setString('displayName', displayName);
在我的 drawerScreen 上,我得到了如下相同的数据:
late String displayName;
initState() {
getData();
super.initState();
}
getData() async{
SharedPreferences prefs = await SharedPreferences.getInstance();
displayName=prefs.getString('displayName')!;
}
但是每当我点击抽屉按钮时都会出现错误,如图所示:
LateInitializationError: Field 'displayName' has not been initialized.
但是当我在抽屉打开时热重载我的应用程序时没有错误当我转到其他屏幕并返回抽屉时出现 LateInitialization 错误,
我不知道是什么导致了这个错误
这是我从抽屉移出的另一个屏幕:
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,
),
),
),
),
),
],
),
),
有人可以建议我更好的方法吗。提前致谢 <3
你的问题是 initState
不是 async
(也不可能是 async
),所以你的 getData
很可能(或肯定)完成晚于调用 build
方法。由于您在 getData
中设置了 displayName
,并将其标记为 late
,因此您会收到此错误。这就是它在热重载后工作的原因,因为那时 displayName
已经初始化。
一个可能的解决方案是在您的应用程序中较早的某个地方调用 SharedPreferences.getInstance()
(这就是为什么您的 getData
需要 async
),例如在 main() async
函数中,使用 ChangeNotifierProvider
(或允许您在此小部件中使用此值的任何其他方式)存储 getInstance
的结果,并在 getData
中使用其值。这样 getData
不需要是 async
,并且 displayName
会在调用 build
方法之前初始化。如果您在多个地方使用 SharedPreferences
,这会很有用,因为您不必每次都 await
getInstance
的结果。
另一种方法是不将 displayName
声明为 late
,而是允许它是 null
,然后在 build
方法中您可以使用 FutureBuilder
在 getData
执行后完成,而 Scaffold
的构建只会在这个未来完成后开始。在这种情况下,您可以在未来未完成时显示进度指示器。
我忘了添加 setState();
late String displayName;
initState() {
getData();
super.initState();
}
Future getData() async{
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
displayName=prefs.getString('displayName')!;
});
}