Kodokon kodokon.com

Persistance locale avec shared_preferences

Persistez préférences et données légères avec shared_preferences en connaissant ses limites de sécurité et de volumétrie.

8 min · 3 questions

Ouvrir cette leçon dans Kodokon

shared_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.

BASH
flutter pub add shared_preferences

getInstance() 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.

DART
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);
}
Clés centralisées, types garantis, dépendance injectable.

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.

DART
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>,
  );
}
Un objet complet stocké comme une simple chaîne JSON.

Quiz de validation

Vérifiez que vous avez bien retenu les points clés de cette leçon.

  1. Quelle donnée relève de shared_preferences ?
    • Le token d'authentification de l'utilisateur.
    • L'historique complet des 50 000 transactions de l'utilisateur.
    • Le choix du thème sombre.
  2. Après le premier getInstance(), comment se comportent les lectures get* ?
    • Chaque lecture relit le fichier sur le disque.
    • Elles sont synchrones : les valeurs sont servies depuis un cache mémoire.
    • Elles retournent des Future qu'il faut attendre à chaque fois.
  3. Comment sauvegarder un objet Draft structuré ?
    • Le sérialiser en JSON avec jsonEncode et le stocker via setString.
    • Utiliser prefs.setObject('draft', draft) prévu à cet effet.
    • Le découper champ par champ dans un setStringList.