Flutter - Keeping variable's value after each app restart

1,177

You have to use the package shared preference. I will edit with an example from my source codes

I would use FutureBuilder instead of initstate as it is cleaner:

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

class SavedPreference extends StatefulWidget {
  SavedPreference({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _SavedPreference createState() => _SavedPreference();
}

class _SavedPreference extends State<SavedPreference> {
  TextEditingController _textEditingController;
  String valueText;

  void initState() {
    super.initState();
  }

  Future<String> _getSharedValue() async {
    const defaultText =
        "This is what i want my default variable to be when my app first opened.";
    String ret;
    var prefs = await SharedPreferences.getInstance();
    bool isFirstTime = prefs.getBool('firstTime');
    print(isFirstTime);

    ret =
        (isFirstTime == null || isFirstTime == true) ? defaultText : prefs.getString('sharedmessage');
    print(ret);

    _textEditingController = new TextEditingController(text: ret);
    return ret;
  }

  String codeDialog;

  void setText() async {
    final prefs = await SharedPreferences.getInstance();
    prefs.setString('sharedmessage', valueText);
    prefs.setBool('firstTime', false);
  }

  @override
  Widget build(BuildContext context) {
    int maxLines = 10;
    return Container(
        child: FutureBuilder(
            future: _getSharedValue(),
            builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
              print(snapshot.data);
              if (snapshot.hasData) {
                return TextButton(
                    child: Text(snapshot.data),
                    onPressed: () async => await showDialog(
                        context: context,
                        builder: (context) => new AlertDialog(
                              scrollable: true,
                              contentPadding:
                                  EdgeInsets.fromLTRB(20, 20, 20, 0),
                              content: Column(
                                children: [
                                  Container(
                                    height: maxLines * 10.0,
                                    child: TextField(
                                      controller: new TextEditingController(
                                          text: codeDialog),
                                      maxLines: maxLines,
                                      onChanged: (value) {
                                        valueText = value;
                                      },
                                      decoration: InputDecoration(
                                        hintText: "Text here",
                                      ),
                                    ),
                                  ),
                                ],
                              ),
                              actions: [
                                TextButton(
                                    onPressed: Navigator.of(context).pop,
                                    child: Text("Cancel")),
                                TextButton(
                                    onPressed: () {
                                      setState(() {
                                        Navigator.pop(context);
                                        codeDialog = valueText;
                                        print(codeDialog);
                                        setText();
                                      });
                                    },
                                    child: Text("Save"))
                              ],
                            )));
              } else
                return CircularProgressIndicator();
            }));
  }
}

Your problem was that initState was not awaiting properly the result of await SharedPreferences.getInstance(); (I tried to fix it inside initState and lost a tremendous amount of time)

Share:
1,177
W33baker
Author by

W33baker

Updated on December 28, 2022

Comments

  • W33baker
    W33baker over 1 year

    On my one page I would like my user to start with default text on one variable ( codeDialog) and then I want them to change that text, after that time that text they wrote would be my new default text. Sadly I couldn't get it to work.

    Right now when I restart the app and open that screen it resets to null. I think its because of initializing variable ( which is null) but I couldn't find a way to fix that. Any idea? Thanks.

    All of this is inside statefulwidget's state class:

    void initState() {
        super.initState();
        print(codeDialog);
        isFirstTime().then((isFirstTime) {
          isFirstTime ? defaultText() : readFromShared();
        });
        setText();
        print(codeDialog);
        _textEditingController = new TextEditingController(text: codeDialog);
      }
    Future<bool> isFirstTime() async {
        final prefs = await SharedPreferences.getInstance();
        var isFirstTime = prefs.getBool('first_time');
        if (isFirstTime != null && !isFirstTime) {
          prefs.setBool('first_time', false);
          return false;
        } else {
          prefs.setBool('first_time', false);
          return true;
        }
      }
      static String codeDialog;
      void defaultText(){
        print("first time");
        codeDialog="This is what i want my default variable to be when my app first opened.";
      }
    
      void readFromShared() async{
        print("not first");
        final prefs = await SharedPreferences.getInstance();
        codeDialog = prefs.getString('sharedmessage');
      }
      void setText() async {
        final prefs = await SharedPreferences.getInstance();
        prefs.setString('sharedmessage', codeDialog);
      }
    

    and then i have AlertDialog with this it works and saves the data.

    AlertDialog(
                scrollable: true,
                contentPadding: EdgeInsets.fromLTRB(20, 20, 20, 0),
                content: Column(
                  children: [
                    Container(
                      height: maxLines * 10.0,
                      child: TextField(
                        controller:  new TextEditingController(text: codeDialog),//_textEditingController,
                        maxLines: maxLines,
                        onChanged: (value){
                          setState(() {
                            valueText=value;
                          });
                        },
                        decoration: InputDecoration(
                          hintText: "Text here",
                        ),
                      ),
                    ),
                  ],
                ),
                actions: [
                  TextButton(
                      onPressed: Navigator.of(context).pop, child: Text("Cancel")),
                  TextButton(
                      onPressed: () {
                        setState(() {
                          Navigator.pop(context);
                          codeDialog = valueText;
                          print(codeDialog);
                          setText();
                        });
                      },
                      child: Text("Save"))
                ],
              )
    

    EDIT: Also worth noting to people who may see this question. If you don't change TextField's value and submit it (After app restart for some reason) the value will change to null (i think due to there's no change in string). You can fix it by adding if(value==null) and saving it if its not null.

    • Ganesh Bhat
      Ganesh Bhat about 3 years
      You can use shared preference to store values and use after app restars. Check this example : suragch.medium.com/…
    • W33baker
      W33baker about 3 years
      I do use shared preference.
  • W33baker
    W33baker about 3 years
    I do use shared preference.
  • W33baker
    W33baker about 3 years
    Thank you for your time. There was slight problem with your code: (isFirstTime == true) ? defaultText : prefs.getString('sharedmessage'); if shared pref never assigned it returns null so changing it with (isFirstTime == null || isFirstTime == true) ? defaultText : prefs.getString('sharedmessage'); solved it and i think your code runs. Again thanks.
  • W33baker
    W33baker about 3 years
    Also worth noting to people who may see this question. If you don't change TextField's value and submit it (After app restart for some reason) the value will change to null (i think due to there's no change in string). You can fix it by adding if(value==null) and saving it if its not null.
  • Antonin GAVREL
    Antonin GAVREL about 3 years
    Please add your edit to my answer W33baker, it is always welcome!