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 方法中您可以使用 FutureBuildergetData 执行后完成,而 Scaffold 的构建只会在这个未来完成后开始。在这种情况下,您可以在未来未完成时显示进度指示器。

我忘了添加 setState();

late String displayName;
initState() {
getData();
super.initState();
 }
 Future getData() async{
 SharedPreferences prefs = await SharedPreferences.getInstance();
 setState(() {
  displayName=prefs.getString('displayName')!;
  });

}