Persistez préférences et données légères avec shared_preferences en connaissant ses limites de sécurité et de volumétrie.
Ouvrir cette leçon dans Kodokonshared_preferences est un stockage clé/valeur adossé aux mécanismes natifs (SharedPreferences sur Android, UserDefaults sur iOS). Son créneau : les petites données - thème choisi, onboarding vu, dernier onglet actif. Au-delà, changez d'outil : une base sqflite ou drift pour les données volumineuses ou interrogeables, flutter_secure_storage pour tout ce qui est sensible. Le fichier est chargé intégralement en mémoire : il n'est ni chiffré, ni fait pour grossir.
flutter pub add shared_preferencesgetInstance() est asynchrone au premier appel (lecture du fichier), puis renvoie une instance en cache : les get* suivants sont synchrones, servis depuis la mémoire. Les set*, eux, écrivent sur disque de façon asynchrone. En pratique, ne semez pas des chaînes de clés dans toute l'application : centralisez-les dans un wrapper typé, injectable et testable.
import 'package:shared_preferences/shared_preferences.dart';
class SettingsStore {
SettingsStore(this._prefs);
static const _darkModeKey = 'settings.darkMode';
final SharedPreferences _prefs;
static Future<SettingsStore> load() async {
final prefs = await SharedPreferences.getInstance();
return SettingsStore(prefs);
}
bool get darkMode =>
_prefs.getBool(_darkModeKey) ?? false;
Future<void> setDarkMode(bool value) =>
_prefs.setBool(_darkModeKey, value);
}L'API ne stocke que des types primitifs : bool, int, double, String et List<String>. Pour un objet structuré, sérialisez-le en JSON - vos toJson/fromJson de la première leçon resservent ici. Compromis assumé : chaque sauvegarde réécrit la valeur entière et aucune requête n'est possible. Parfait pour un brouillon, inadapté à un historique.
import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';
class Draft {
const Draft({required this.title, required this.body});
factory Draft.fromJson(Map<String, dynamic> json) =>
Draft(
title: json['title'] as String,
body: json['body'] as String,
);
final String title;
final String body;
Map<String, dynamic> toJson() =>
{'title': title, 'body': body};
}
Future<void> saveDraft(Draft draft) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('draft', jsonEncode(draft));
}
Future<Draft?> loadDraft() async {
final prefs = await SharedPreferences.getInstance();
final raw = prefs.getString('draft');
if (raw == null) return null;
return Draft.fromJson(
jsonDecode(raw) as Map<String, dynamic>,
);
}shared_preferences ?getInstance(), comment se comportent les lectures get* ?Future qu'il faut attendre à chaque fois.Draft structuré ?jsonEncode et le stocker via setString.prefs.setObject('draft', draft) prévu à cet effet.setStringList.