Usually mobile apps have data stored on the local device. Like a token to detect whether the user is logged in or not in the application. With it, users don’t need to log in every time they open the application. In Flutter, we can use shared_preferences to save data to a locale that has a key-value pair. This package will wrap native functionality such as SharedPreferences on Android and UserDefaults on iOS.
This blog is part of blogs about handling local data on Flutter:
- [This Blog] Local storage with shared_preferences in Flutter
- [English version soon] Penyimpanan data lokal pada Flutter (sqflite)
- [English version soon] Cara untuk melakukan migration pada SQFLite
Alright, let’s go to the code, Yuk Ngoding.
1. Adding package
In pubspec.yaml, add the shared_preferences package and run “flutter pub get” in cmd.
shared_preferences: ^2.1.2
2. shared_preferences.dart
Usually we create custom classes to handle local data. Create a file with MySharedPref.Dart as name and add code like below:
import 'package:shared_preferences/shared_preferences.dart';
import '../../models/example_model.dart';
class MySharedPref {
static const String keyValue = "value";
static const String keyExampleModel = "exampleModel";
Future<SharedPreferences> getPreferences() async =>
await SharedPreferences.getInstance();
setValue(String value) async {
(await getPreferences()).setString(keyValue, value);
/// Other than strings
// (await getPreferences()).setInt(keyValue, 10);
// (await getPreferences()).setBool(keyValue, true);
// (await getPreferences()).setDouble(keyValue, 1.5);
// (await getPreferences()).setStringList(keyValue, <String>['Earth', 'Moon', 'Sun']);
}
Future<String?> getValue() async {
/// Other than strings
// final int? counter = (await getPreferences()).getInt(keyValue);
// final bool? repeat = (await getPreferences()).getBool(keyValue);
// final double? decimal = (await getPreferences()).getDouble(keyValue);
// final List<String>? items = (await getPreferences()).getStringList(keyValue);
return (await getPreferences()).getString(keyValue);
}
setModel(ExampleModel model) async {
(await getPreferences())
.setString(keyExampleModel, exampleModelToJson(model));
}
Future<ExampleModel?> getModel() async {
var data = (await getPreferences()).getString(keyExampleModel);
if (data != null) return exampleModelFromJson(data);
return null;
}
Future<bool> clearAllData() async {
var sharedPref = await SharedPreferences.getInstance();
sharedPref.remove(keyValue);
sharedPref.remove(keyExampleModel);
return true;
}
}
- keyValue and keyExampleModel are the keys we use to retrieve values from SharedPreferences
- The getPreferences() method is used to get the SharedPreferences object used to manage local data
- setValue and getValue are simple examples of storing values of type String
- setModel and getModel are examples of converting objects to Strings, so we can store their values into SharedPreferences
- clearAllData method is used to clear all data from SharedPreferences
* Tips: use quicktype or javiercbk to make it easier to convert json object to dart class.
It’s in one of the model class instances
// To parse this JSON data, do
//
// final exampleModel = exampleModelFromJson(jsonString);
import 'dart:convert';
ExampleModel exampleModelFromJson(String str) =>
ExampleModel.fromJson(json.decode(str));
String exampleModelToJson(ExampleModel data) => json.encode(data.toJson());
class ExampleModel {
ExampleModel({
required this.greeting,
required this.instructions,
});
String greeting;
List<String> instructions;
factory ExampleModel.fromJson(Map<String, dynamic> json) => ExampleModel(
greeting: json["greeting"],
instructions: List<String>.from(json["instructions"].map((x) => x)),
);
Map<String, dynamic> toJson() => {
"greeting": greeting,
"instructions": List<dynamic>.from(instructions.map((x) => x)),
};
}
3. Screen
Use this code for screen / UI
import 'package:flutter/material.dart';
import '../repository/local/shared_preferences.dart';
class ExampleScreen extends StatefulWidget {
const ExampleScreen({super.key});
@override
State<ExampleScreen> createState() => _ExampleScreenState();
}
class _ExampleScreenState extends State<ExampleScreen> {
final MySharedPref _mySharedPref = MySharedPref();
String _value = "Empty";
final TextEditingController _inputController = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Explore SharedPreferences"),
),
body: Container(
margin: const EdgeInsets.symmetric(
vertical: 12,
horizontal: 16,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: [
const Text(
"Save value",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 24,
),
),
Container(
margin: const EdgeInsets.only(
bottom: 8,
),
child: TextField(
controller: _inputController,
),
),
ElevatedButton(
onPressed: () {
_mySharedPref.setValue(_inputController.value.text);
_inputController.text = "";
},
child: const Text("Save"),
),
Container(
margin: const EdgeInsets.only(top: 32, bottom: 8),
child: const Text(
"Get Value",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 24,
),
),
),
Container(
margin: const EdgeInsets.only(bottom: 8),
child: Center(
child: Text("Value: $_value"),
),
),
ElevatedButton(
onPressed: () {
setState(() {
_mySharedPref.getValue().then((value) {
if (value != null) _value = value;
});
});
},
child: const Text("Get"),
)
],
),
),
);
}
}
After that, call ExampleScreen, so we can see the output like this:
Thats all guys. This blog is part of blogs about handling local data on Flutter:
- [This Blog] Local storage with shared_preferences in Flutter
- [English version soon] Penyimpanan data lokal pada Flutter (sqflite)
- [English version soon] Cara untuk melakukan migration pada SQFLite
Hopefully this blog can help everyone 😀