flutterflutter-providerflutter-sharedpreference

using Shared preferences with a change notifier


I'm trying to understand how to use shared preferences with a change notifier. I've created a basic app and I want to save a bool and a string from the change notifier using shared preferences. here is my main.dart:

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

void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => GlobalSettings1()),
        ChangeNotifierProvider(create: (_) => SectionSettings1()),
      ],
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        debugShowCheckedModeBanner: false,
        initialRoute: '/seventh',
        routes: {
          '/': (context) => Page01(),
          '/first': (context) => Page02(),
          '/second': (context) => Page03(),
        });
  }
}

and here is page01

class _Page01State extends State<Page01> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          InkWell(
            onTap: () {
              context.read<GlobalSettings1>().ToggleSwitch();
            },
            child: Container(
              height: 30,
              width: 80,
              color: context.watch<GlobalSettings1>().toggleSwitch01
                  ? Colors.green
                  : Colors.red,
            ),
          ),
          SizedBox(
            height: 20,
          ),
          InkWell(
              onTap: () {
                showDialog(
                  context: context,
                  builder: (BuildContext context) => Material(
                    color: Colors.transparent,
                    child: Buttons(
                      onTap: (val) {
                        context.read<GlobalSettings1>().StringToSave(val);
                        Navigator.pop(context);
                      },
                    ),
                  ),
                );
              },
              child: Container(
                height: 30,
                width: 80,
                child: Center(
                  child: Text(
                    context.watch()<GlobalSettings1>().stringToSave,
                  ),
                ),
              )),
        ],
      ),
    );
  }
}

and finally, here is my change notifier:

class Buttons extends StatelessWidget {
  const Buttons({Key? key, required this.onTap}) : super(key: key);
  final ValueChanged? onTap;

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        InkWell(
            onTap: () {
              if (onTap != null) {
                onTap!('Choice01');
              }
            },
            child: Container(
              height: 30,
              width: 80,
              child: Text('Choice01'),
            )),
        SizedBox(
          height: 30,
        ),
        InkWell(
            onTap: () {
              if (onTap != null) {
                onTap!('Choice02');
              }
            },
            child: Container(
              height: 30,
              width: 80,
              child: Text('Choice02'),
            )),
      ],
    );
  }
}

class GlobalSettings1 with ChangeNotifier {
  bool _toggleSwitch01 = true;
  String _stringToSave = 'Choice01';

  final SharedPreferences prefs;

  GlobalSettings1({required this.prefs});

  bool get toggleSwitch01 => _toggleSwitch01;
  String get stringToSave => _stringToSave;

  void ToggleSwitch() {
    _toggleSwitch01 = !_toggleSwitch01;
    _setPrefItems();
    notifyListeners();
  }

  void StringToSave(val) {
    _stringToSave = val;
    _setPrefItems();
    notifyListeners();
  }

  void _setPrefItems() {
    prefs.setBool('toggleSwitch01', _toggleSwitch01);
    prefs.setString('stringToSave', _stringToSave);
    notifyListeners();
  }

  void _getPrefItems() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    _stringToSave = prefs.getString('stringToSave') ?? '';
    _toggleSwitch01 = prefs.getBool('autoUpdateVariables') ?? true;
    notifyListeners();
  }

  bool getToggleSwitch01() {
    _getPrefItems();
    return _toggleSwitch01;
  }

  String getStringToSave() {
    _getPrefItems();
    return _stringToSave;
  }
}

As you can see, there is a bool that is toggled in Page01 and a String that is displayed from a value that is generated and passed through from the buttons widget.

After looking at other tutorials on this matter, I think i have the change notifier set up correctly but am unsure about how to set up the main.dart and Page01 so that when the bool and String are set, they stay like that when the app is rebooted.

i'm currently getting an error in main.dart:

ChangeNotifierProvider(create: (_) => GlobalSettings1()),

asking me to add required argument prefs but i'm unsure what the code should be to go in the brackets.

thanks so much and any help would be greatly appreciated.


Solution

  • You need pass an instance of SharedPreferences to your GlobalSettings1, also change GlobalSettings1 to this:

    class GlobalSettings1 with ChangeNotifier {
      bool _toggleSwitch01 = true;
      String _stringToSave = 'Choice01';
    
      final SharedPreferences prefs;
    
      GlobalSettings1({required this.prefs});
    
      bool get toggleSwitch01 => _toggleSwitch01;
      String get stringToSave => _stringToSave;
    
      void ToggleSwitch() {
        _toggleSwitch01 = !_toggleSwitch01;
        _setPrefItems();
        notifyListeners();
      }
    
      void StringToSave(val) {
        _stringToSave = val;
        _setPrefItems();
        notifyListeners();
      }
    
      void _setPrefItems() {
        prefs.setBool('toggleSwitch01', _toggleSwitch01);
        prefs.setString('stringToSave', _stringToSave);
        notifyListeners();
      }
    
      void _getPrefItems() { // <=== change this
        _stringToSave = prefs.getString('stringToSave') ?? '';
        _toggleSwitch01 = prefs.getBool('autoUpdateVariables') ?? true;
        notifyListeners();
      }
    
      bool getToggleSwitch01() {
        _getPrefItems();
        return _toggleSwitch01;
      }
    
      String getStringToSave() {
        _getPrefItems();
        return _stringToSave;
      }
    }
    

    then change your main to this:

    void main() {   
        SharedPreferences prefs = await SharedPreferences.getInstance();
        runApp(
            MultiProvider(
              providers: [
                ChangeNotifierProvider(create: (_) => GlobalSettings1(prefs: prefs)),
                ChangeNotifierProvider(create: (_) => SectionSettings1()),
              ],
              child: MyApp(),
            ),
        );
    }