Skip to content

Shared preferences example

SharedPreferences is a package that allows you to store key-value pairs on the device. This example shows how to provide a SharedPreferences object, after initialization, to the whole app using Disco. After the initialization, the preferences can be retrieved and updated synchronously.

You can take inspiration to provide other asynchronous objects.

Dependency

This is the shared_preferences version used in the following example:

dependencies:
shared_preferences: ^2.4.0

Example

The code below handles the loading and error states of the initialization process correctly and it’s the preferred way for handling async initialization in Flutter.

main.dart
import 'package:disco/disco.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() {
runApp(const InitializationPage());
}
final sharedPreferencesProvider = Provider.withArgument(
(context, SharedPreferences prefs) => prefs,
);
class InitializationPage extends StatefulWidget {
const InitializationPage({super.key});
@override
State<InitializationPage> createState() => _InitializationPageState();
}
class _InitializationPageState extends State<InitializationPage> {
late final initialization = Future(() async {
// Artificial delay to simulate loading
await Future.delayed(Duration(seconds: 3));
// Initialize shared preferences
final prefs = await SharedPreferences.getInstance();
return (preferences: prefs);
});
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: initialization,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Directionality(
textDirection: TextDirection.ltr,
child: Center(
child: Text('Error: ${snapshot.error}'),
),
);
}
final data = snapshot.data!;
return ProviderScope(
providers: [
sharedPreferencesProvider(data.preferences),
],
child: MyApp(),
);
},
);
}
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
final sharedPreferences = sharedPreferencesProvider.of(context);
final counter = sharedPreferences.getInt('counter') ?? 0;
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: Scaffold(
body: Center(
child: Text("The counter is $counter"),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
sharedPreferences.setInt('counter', counter + 1);
});
},
child: const Icon(Icons.add),
),
),
);
}
}

Alternative example (without error handling)

If you know the initialization cannot fail, or it takes just a fraction of a second and you don’t want to show the loading state, you can simplify the code as follows:

Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
final prefs = await SharedPreferences.getInstance();
runApp(
ProviderScope(
providers: [
sharedPreferencesProvider(prefs),
],
child: MyApp(),
),
);
}