Flutter: MVVM architecture with Shared Preferences & Provider
855
Here is a comprehensive example, below. Notes:
- There is no need to pass
SharedPreferences
to your model as it has a static method to get the instance. - I use
Provider.of<LanguagePreferenceVM>
to get the provider to update the language. - I use
Consumer<LanguagePreferenceVM>
to get the provider to display the language when it notifies listeners. - I use
FutureBuilder
to handle theasync
result.
Example code:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
class LanguagePreference {
SharedPreferences _prefs;
Future<void> getSharedPreferences() async {
if (_prefs == null) {
_prefs = await SharedPreferences.getInstance();
}
}
LanguagePreference();
Future<void> addUserLanguage(String lang) async {
await getSharedPreferences();
_prefs.setString('userLanguage', "$lang");
}
Future<String> getUserLanguage() async {
//Return String
try {
await getSharedPreferences();
var language = _prefs.getString('userLanguage');
return language;
} catch (e) {
return '';
}
}
}
class LanguagePreferenceVM extends ChangeNotifier {
LanguagePreference languagePreference;
LanguagePreferenceVM({@required this.languagePreference});
String userLanguage = '';
Future<void> setUserLanguage(String newUserLanguage) async {
await languagePreference.addUserLanguage(newUserLanguage);
userLanguage = newUserLanguage;
}
Future<String> getUserLanguage() async {
userLanguage = await languagePreference.getUserLanguage();
return userLanguage;
}
}
class PrefsTest extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<LanguagePreferenceVM>(
create: (ctx) =>
LanguagePreferenceVM(languagePreference: LanguagePreference()),
),
],
child: PrefsTest2(),
);
}
}
class PrefsTest2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
var languagePreferenceVM =
Provider.of<LanguagePreferenceVM>(context, listen: false);
languagePreferenceVM.setUserLanguage('English');
return Scaffold(
appBar: AppBar(title: Text('Prefs')),
body: Consumer<LanguagePreferenceVM>(
builder: (ctx, languagePreferenceVM, child) => FutureBuilder(
future: languagePreferenceVM.getUserLanguage(),
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return const CircularProgressIndicator();
default:
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return Text('User language: ${snapshot.data}');
}
}
},
),
),
);
}
}
Author by
Ang Xing
Updated on December 29, 2022Comments
-
Ang Xing over 1 year
I am trying to build a reusable function of Shared Preference & provider using MVVM architecture. However, I not sure how to initialize the ChangeNotifierProvider at my main. dart file. Below is the code I have.
class LanguagePreference { SharedPreferences prefs; LanguagePreference({required this.prefs}); addUserLanguage(String lang) async { await SharedPreferences.getInstance(); prefs.setString('userLanguage', "$lang"); } getUserLanguage() async { SharedPreferences prefs = await SharedPreferences.getInstance(); //Return String return prefs.getString('userLanguage'); } }
class LanguagePreferenceVM extends ChangeNotifier { LanguagePreference languagepreference; LanguagePreferenceVM({required this.languagePreference}); String userLanguage = ''; addUserLanguage(String newUserLanguage) async { await languagePreference.addUserLanguage(newUserLanguage); } getUserLanguage() async { userLanguage = await languagePreference.getUserLanguage(); notifyListeners(); } }
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MultiProvider( providers: [], child: MaterialApp( ), ); } }
-
Ang Xing about 3 yearsI need to pass in my model class to initialise my ChangeNotifierProvider and my model class require me to pass in a shared preference. I am stuck here.
-
Patrick O'Hara about 3 yearsI expanded the answer