Using Shared preferences in InitState of Widget causes Error

1.3k Views Asked by At

I want to render the value saved in key of object of SharedPreference Class in the App Bar as Text for which I have to declare the following code in the initState of the widget.

initState() {
    // TODO: implement initState
    super.initState();
    debugPrint("Runed");
    _getPrefs();
    SharedPreferences.getInstance().then((prefs) {
      setState(() => prefs = prefs);
    });
    
  }

My _getPrefs() code is:

 SharedPreferences prefs;

  Future<dynamic> _getPrefs() async {
    prefs = await SharedPreferences.getInstance();
    return prefs;
  }

and my AppBar code is:

appBar: AppBar(
        title: Text(prefs.getString("username")),
        centerTitle: true,
      ),

Body of the widget:

  body: ListView(
        children: [
          FutureBuilder(
              future: _getPrefs(),
              builder: (context, snapshot) {
                if (snapshot.hasData) {
                  return Column(
                    mainAxisAlignment: MainAxisAlignment.start,
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: <Widget>[
                      Padding(
                        padding: EdgeInsets.only(left: 5, top: 5, right: 5),
                        child: Container(
                          width: double.infinity,
                          padding: EdgeInsets.only(left: 5),
                          decoration: BoxDecoration(
                            color: Colors.white54,
                            shape: BoxShape.rectangle,
                            borderRadius: BorderRadius.circular(25.0),
                            boxShadow: [
                              BoxShadow(blurRadius: 2, color: Colors.white)
                            ],
                          ),
                          child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: <Widget>[
                              Container(
                                width: 100,
                                height: 100,
                                margin: EdgeInsets.only(
                                    top: 3, left: 10, bottom: 10),
                                decoration: BoxDecoration(
                                  color: Colors.white,
                                  shape: BoxShape.circle,
                                  image: DecorationImage(
                                      image: NetworkImage(
                                          prefs.getString("photoUrl")),
                                      fit: BoxFit.fill),
                                ),
                              ),


                              Column(
                                crossAxisAlignment: CrossAxisAlignment.start,
                                children: [
                                  Text(
                                    prefs.getString("username"),
                                    style: TextStyle(
                                        fontSize: 22,
                                        color: Colors.black45,
                                        fontWeight: FontWeight.bold),
                                  ),
                                  Text(prefs.getString("email"))
                                ],
                              ),


                              /*  Text(
                            prefs.getString("email").toString(),
                            style: TextStyle(fontSize: 18, color: Colors.white70),
                          )*/
                            ],
                          ),
                        ),
                      ),
                    ],
                  );
                } else {
                  return Center(child: Text('False'));
                }
              }),
        ],
      ),

I do get the results successfully while navigating from one screen to the screen where I want to render the text in AppBar but some error does show in the console which is annoying. Please help by telling the reason and solution! Erron in console is this:

Reloaded 14 of 873 libraries in 3,092ms.
I/flutter (20249): Runed

════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following NoSuchMethodError was thrown building ProfileDetail(dirty, state: _ProfileDetailState#6aebe):
The method 'getString' was called on null.
Receiver: null
Tried calling: getString("username")

The relevant error-causing widget was: 
  ProfileDetail file:///D:/All%20Data/My%20Projects/Mine%20Created%20Flutter%20Projects/food_delivery_app/lib/main.dart:268:53
When the exception was thrown, this was the stack: 
#0      Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
#1      _ProfileDetailState.build (package:food_delivery_app/ProfileDetails/profileDetail.dart:36:27)
#2      StatefulElement.build (package:flutter/src/widgets/framework.dart:4744:28)
#3      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4627:15)
#4      StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4800:11)
...
════════════════════════════════════════════════════════════════════════════════════════════════════
1

There are 1 best solutions below

0
On

The problem is that SharedPreferences.getInstance is async, but you are calling it in a sync method where you cannot await. Therefore, your AppBar is being built before SharedPreferences.getInstance returns, meaning prefs is null.

A simple solution is to null check prefs and return a blank or default string until setState is called with a non-null prefs.

appBar: AppBar(
  title: Text(prefs?.getString("username") ?? ''),
  centerTitle: true,
),