↑
CHAPITRE 5.1

Stockage simple avec SharedPreferences

Sauvegarder et récupérer des données simples dans votre application Flutter
Dans cette section, vous allez découvrir SharedPreferences, un mécanisme simple et efficace pour stocker des données de type clé-valeur dans votre application Flutter. C'est la solution idéale pour sauvegarder des préférences utilisateur, des paramètres, ou de petites quantités de données. Nous verrons comment l'installer, l'utiliser, et quelles sont ses limites. 💾

5.1Stockage simple avec SharedPreferences

5.1.1 – Présentation de SharedPreferences

🎯 Qu'est-ce que SharedPreferences ?

SharedPreferences est un package Flutter qui permet de stocker des données simples sous forme de paires clé-valeur. Il s'agit d'une solution de stockage persistant, ce qui signifie que les données sont conservées même après la fermeture de l'application.

Ce mécanisme est particulièrement adapté pour :

  • Les prĂ©fĂ©rences utilisateur : thème (clair/sombre), langue, notifications activĂ©es/dĂ©sactivĂ©es
  • Les paramètres de l'application : volume par dĂ©faut, qualitĂ© d'affichage, mode de connexion
  • Les petits compteurs ou Ă©tats : nombre de fois que l'application a Ă©tĂ© ouverte, dernière version vue
  • Les donnĂ©es de session simples : nom d'utilisateur, token d'authentification (pour des cas non sensibles)
Comment ça fonctionne ?
SharedPreferences utilise le stockage natif de chaque plateforme :
  • Sur Android : il utilise les SharedPreferences natifs d'Android (fichiers XML)
  • Sur iOS : il utilise NSUserDefaults
  • Sur Web : il utilise localStorage du navigateur
Le package Flutter fait abstraction de ces différences et vous offre une API unifiée. 🔧

📊 Types de données supportés

SharedPreferences peut stocker les types de données suivants :

  • String : chaĂ®nes de caractères
  • int : nombres entiers
  • double : nombres dĂ©cimaux
  • bool : valeurs boolĂ©ennes (true/false)
  • List<String> : listes de chaĂ®nes de caractères
Limitation importante
SharedPreferences ne peut stocker que des types primitifs. Si vous avez besoin de stocker des objets complexes (comme une liste d'utilisateurs avec plusieurs propriétés), vous devrez soit :
  • Convertir vos objets en JSON et les stocker comme des String
  • Utiliser une solution plus adaptĂ©e comme SQLite ou Hive

âś… Avantages de SharedPreferences

  • SimplicitĂ© : API très simple Ă  utiliser, pas besoin de configuration complexe
  • RapiditĂ© : accès très rapide aux donnĂ©es
  • LĂ©ger : pas de surcharge, idĂ©al pour de petites quantitĂ©s de donnĂ©es
  • Persistance : les donnĂ©es survivent aux redĂ©marrages de l'application
  • Cross-platform : fonctionne de la mĂŞme manière sur Android, iOS et Web

❌ Limites de SharedPreferences

  • Types limitĂ©s : seulement des types primitifs, pas d'objets complexes
  • Pas de requĂŞtes : impossible de faire des recherches ou filtres complexes
  • Pas de relations : pas de base de donnĂ©es relationnelle
  • Performance : peut devenir lent avec beaucoup de donnĂ©es (plusieurs milliers d'entrĂ©es)
  • SĂ©curitĂ© : les donnĂ©es ne sont pas chiffrĂ©es (utilisez Secure Storage pour les donnĂ©es sensibles)
Quand utiliser SharedPreferences ?
Utilisez SharedPreferences si vous avez besoin de stocker :
  • Moins de 100-200 paires clĂ©-valeur
  • Des donnĂ©es simples (String, int, bool, etc.)
  • Des prĂ©fĂ©rences utilisateur ou des paramètres
  • Des donnĂ©es non sensibles
Si vous dépassez ces limites, considérez SQLite, Hive ou une autre solution de stockage.

5.1.2 – Installation et configuration du package

🎯 Objectif

Installer le package SharedPreferences dans votre projet Flutter et le configurer correctement.

đź’ˇ Installation pas Ă  pas

Étape 1 : Ajouter la dépendance

Ouvrez le fichier pubspec.yaml de votre projet Flutter et ajoutez la dépendance shared_preferences dans la section dependencies :

dependencies:
  flutter:
    sdk: flutter
  shared_preferences: ^2.2.2
Version du package
La version peut varier. Pour obtenir la dernière version, consultez pub.dev/packages/shared_preferences ou utilisez la commande :
flutter pub add shared_preferences
Cette commande ajoute automatiquement la dernière version compatible.

Étape 2 : Installer le package

Exécutez la commande suivante dans votre terminal, à la racine de votre projet Flutter :

flutter pub get
✅ Résultat attendu : Vous devriez voir un message indiquant que le package a été installé avec succès.

Étape 3 : Importer le package

Dans le fichier Dart oĂą vous souhaitez utiliser SharedPreferences, ajoutez l'import en haut du fichier :

import 'package:shared_preferences/shared_preferences.dart';

📖 Vérifier l'installation

Pour vérifier que le package est correctement installé, créez un fichier de test et essayez d'importer le package :
import 'package:shared_preferences/shared_preferences.dart';

void main() {
  print('SharedPreferences est prêt à être utilisé !');
}
Si aucune erreur n'apparaît, l'installation est réussie. ✅
đź’ˇ Astuce
Si vous utilisez VS Code ou Android Studio, l'IDE vous proposera automatiquement d'importer le package lorsque vous taperez SharedPreferences dans votre code. C'est très pratique !

5.1.3 – Sauvegarder des données simples

Pour sauvegarder des données avec SharedPreferences, vous devez d'abord obtenir une instance, puis utiliser les méthodes set* correspondantes au type de données que vous voulez stocker.

📝 Qu'est-ce que la sauvegarde avec SharedPreferences ?

La sauvegarde consiste à stocker des données dans la mémoire persistante de l'appareil. Ces données seront conservées même après la fermeture de l'application.

Analogie :
SharedPreferences est comme un tiroir avec des étiquettes. Vous mettez une valeur dans un tiroir étiqueté avec une clé (par exemple "username"), et vous pouvez la récupérer plus tard en utilisant cette même clé.

📝 Syntaxe

Voici comment obtenir une instance de SharedPreferences et sauvegarder des données :

// Obtenir une instance (opération asynchrone)
SharedPreferences prefs = await SharedPreferences.getInstance();

// Sauvegarder une String
await prefs.setString('username', 'john_doe');

// Sauvegarder un int
await prefs.setInt('age', 25);

// Sauvegarder un double
await prefs.setDouble('price', 19.99);

// Sauvegarder un bool
await prefs.setBool('isDarkMode', true);

// Sauvegarder une liste de String
await prefs.setStringList('favoriteColors', ['red', 'blue', 'green']);

Analysons cette syntaxe :

  • SharedPreferences.getInstance() : Obtient une instance de SharedPreferences (opĂ©ration asynchrone)
  • setString(key, value) : Sauvegarde une chaĂ®ne de caractères
  • setInt(key, value) : Sauvegarde un nombre entier
  • setDouble(key, value) : Sauvegarde un nombre dĂ©cimal
  • setBool(key, value) : Sauvegarde une valeur boolĂ©enne
  • setStringList(key, value) : Sauvegarde une liste de chaĂ®nes
Pourquoi async/await ?
L'initialisation de SharedPreferences nécessite l'accès au système de fichiers, ce qui est une opération asynchrone. C'est pourquoi vous devez utiliser await et que votre fonction doit être async. 🔄

🧪 Exemple : Sauvegarder des préférences utilisateur

Voici un exemple complet qui sauvegarde les préférences d'un utilisateur :

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main() {
  runApp(const MonApp());
}

class MonApp extends StatelessWidget {
  const MonApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: const MaPage(),
    );
  }
}

class MaPage extends StatefulWidget {
  const MaPage({super.key});

  @override
  State<MaPage> createState() => _MaPageState();
}

class _MaPageState extends State<MaPage> {
  final _nomController = TextEditingController();
  final _ageController = TextEditingController();

  Future<void> sauvegarderPreferences() async {
    // Obtenir une instance
    SharedPreferences prefs = await SharedPreferences.getInstance();
    
    // Sauvegarder différentes données
    await prefs.setString('nom', _nomController.text);
    await prefs.setInt('age', int.tryParse(_ageController.text) ?? 0);
    await prefs.setBool('themeSombre', true);
    await prefs.setDouble('volume', 0.75);
    
    // Afficher un message de confirmation
    if (mounted) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Préférences sauvegardées !')),
      );
    }
  }

  @override
  void dispose() {
    _nomController.dispose();
    _ageController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Sauvegarder avec SharedPreferences'),
      ),
      body: SafeArea(
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Column(
            children: [
              TextField(
                controller: _nomController,
                decoration: const InputDecoration(
                  labelText: 'Nom',
                  border: OutlineInputBorder(),
                ),
              ),
              const SizedBox(height: 16),
              TextField(
                controller: _ageController,
                decoration: const InputDecoration(
                  labelText: 'Âge',
                  border: OutlineInputBorder(),
                ),
                keyboardType: TextInputType.number,
              ),
              const SizedBox(height: 24),
              ElevatedButton(
                onPressed: sauvegarderPreferences,
                child: const Text('Sauvegarder'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Dans cet exemple, quand l'utilisateur clique sur "Sauvegarder", les données sont stockées dans SharedPreferences et un message de confirmation s'affiche.

Vérifier le succès :
Toutes les méthodes set* retournent un bool qui indique si la sauvegarde a réussi. Vous pouvez vérifier ce retour pour gérer les erreurs :
bool success = await prefs.setString('username', 'john_doe');
if (success) {
  print('Données sauvegardées avec succès !');
} else {
  print('Erreur lors de la sauvegarde');
}
Important :
N'oubliez pas que les opérations avec SharedPreferences sont asynchrones. Vous devez toujours utiliser await et déclarer votre fonction comme async.

💡 À propos de mounted :
Avant d'appeler setState après une opération asynchrone, vérifiez toujours if (mounted). Cela permet d'éviter des erreurs si le widget a été retiré de l'arbre Flutter.

5.1.4 – Récupérer des données stockées

Pour récupérer des données sauvegardées avec SharedPreferences, vous utilisez les méthodes get* correspondantes au type de données que vous avez stocké.

📖 Qu'est-ce que la récupération de données ?

La récupération consiste à lire les données que vous avez précédemment sauvegardées. Ces données sont lues depuis la mémoire persistante de l'appareil.

Analogie :
C'est comme ouvrir un tiroir étiqueté pour récupérer ce que vous y avez mis. Si le tiroir est vide (la clé n'existe pas), vous obtenez null.

📝 Syntaxe

Voici comment récupérer différents types de données :

// Obtenir une instance
SharedPreferences prefs = await SharedPreferences.getInstance();

// Récupérer une String (retourne null si la clé n'existe pas)
String? username = prefs.getString('username');
String username = prefs.getString('username') ?? 'Guest'; // Avec valeur par défaut

// Récupérer un int
int? age = prefs.getInt('age');
int age = prefs.getInt('age') ?? 0; // Avec valeur par défaut

// Récupérer un double
double? price = prefs.getDouble('price');
double price = prefs.getDouble('price') ?? 0.0; // Avec valeur par défaut

// Récupérer un bool
bool? isDarkMode = prefs.getBool('isDarkMode');
bool isDarkMode = prefs.getBool('isDarkMode') ?? false; // Avec valeur par défaut

// Récupérer une liste de String
List<String>? colors = prefs.getStringList('favoriteColors');
List<String> colors = prefs.getStringList('favoriteColors') ?? []; // Avec valeur par défaut

Analysons cette syntaxe :

  • getString(key) : RĂ©cupère une chaĂ®ne de caractères (retourne null si la clĂ© n'existe pas)
  • getInt(key) : RĂ©cupère un nombre entier
  • getDouble(key) : RĂ©cupère un nombre dĂ©cimal
  • getBool(key) : RĂ©cupère une valeur boolĂ©enne
  • getStringList(key) : RĂ©cupère une liste de chaĂ®nes
  • ?? : OpĂ©rateur qui fournit une valeur par dĂ©faut si le rĂ©sultat est null

🧪 Exemple : Récupérer et afficher des préférences

Voici un exemple complet avec deux TextField (nom et âge) et un Switch (thème sombre). Les valeurs sont automatiquement chargées au démarrage et sauvegardées à chaque modification :

Exemple SharedPreferences Flutter
Exemple SharedPreferences Flutter.
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main() {
  runApp(const MonApp());
}

class MonApp extends StatelessWidget {
  const MonApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: const MaPage(),
    );
  }
}

class MaPage extends StatefulWidget {
  const MaPage({super.key});

  @override
  State<MaPage> createState() => _MaPageState();
}

class _MaPageState extends State<MaPage> {
  final _nomController = TextEditingController();
  final _ageController = TextEditingController();
  bool themeSombre = false;

  @override
  void initState() {
    super.initState();
    chargerPreferences();
  }

  // Charger les préférences au démarrage
  Future<void> chargerPreferences() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    
    setState(() {
      // Récupérer le nom (valeur par défaut : chaîne vide)
      _nomController.text = prefs.getString('nom') ?? '';
      
      // Récupérer l'âge (valeur par défaut : 0)
      int age = prefs.getInt('age') ?? 0;
      _ageController.text = age > 0 ? age.toString() : '';
      
      // Récupérer l'état du thème (valeur par défaut : false)
      themeSombre = prefs.getBool('themeSombre') ?? false;
    });
  }

  // Sauvegarder le nom quand il change
  Future<void> sauvegarderNom(String valeur) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setString('nom', valeur);
  }

  // Sauvegarder l'âge quand il change
  Future<void> sauvegarderAge(String valeur) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    int age = int.tryParse(valeur) ?? 0;
    await prefs.setInt('age', age);
  }

  // Sauvegarder l'état du thème quand il change
  Future<void> sauvegarderTheme(bool valeur) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setBool('themeSombre', valeur);
  }

  @override
  void dispose() {
    _nomController.dispose();
    _ageController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Préférences persistantes'),
      ),
      body: SafeArea(
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              // TextField pour le nom
              TextField(
                controller: _nomController,
                decoration: const InputDecoration(
                  labelText: 'Nom',
                  border: OutlineInputBorder(),
                  hintText: 'Entrez votre nom',
                ),
                onChanged: (valeur) {
                  // Sauvegarder automatiquement Ă  chaque modification
                  sauvegarderNom(valeur);
                },
              ),
              const SizedBox(height: 16),
              
              // TextField pour l'âge
              TextField(
                controller: _ageController,
                decoration: const InputDecoration(
                  labelText: 'Âge',
                  border: OutlineInputBorder(),
                  hintText: 'Entrez votre âge',
                ),
                keyboardType: TextInputType.number,
                onChanged: (valeur) {
                  // Sauvegarder automatiquement Ă  chaque modification
                  sauvegarderAge(valeur);
                },
              ),
              const SizedBox(height: 24),
              
              // Switch pour le thème sombre
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  const Text(
                    'Thème sombre',
                    style: TextStyle(fontSize: 18),
                  ),
                  Switch(
                    value: themeSombre,
                    onChanged: (bool valeur) {
                      setState(() {
                        themeSombre = valeur;
                      });
                      // Sauvegarder automatiquement quand le switch change
                      sauvegarderTheme(valeur);
                    },
                  ),
                ],
              ),
              const SizedBox(height: 24),
              
              // Message informatif
              Container(
                padding: const EdgeInsets.all(12),
                decoration: BoxDecoration(
                  color: Colors.blue.shade50,
                  borderRadius: BorderRadius.circular(8),
                ),
                child: const Text(
                  '💡 Les valeurs sont automatiquement sauvegardées et seront restaurées au prochain démarrage de l\'application.',
                  style: TextStyle(fontSize: 14),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Dans cet exemple :

  • Au dĂ©marrage : Les valeurs sauvegardĂ©es (nom, âge, thème) sont chargĂ©es depuis SharedPreferences et affichĂ©es dans les TextField et le Switch
  • Ă€ chaque modification : Quand l'utilisateur modifie un TextField ou le Switch, la valeur est automatiquement sauvegardĂ©e dans SharedPreferences
  • Persistance : Si vous fermez et rouvrez l'application, toutes les valeurs seront restaurĂ©es automatiquement
Comment ça fonctionne :
  • initState() : Appelle chargerPreferences() au dĂ©marrage pour charger les valeurs sauvegardĂ©es
  • onChanged : Sur chaque TextField, sauvegarde automatiquement la valeur Ă  chaque modification
  • onChanged du Switch : Met Ă  jour l'Ă©tat et sauvegarde immĂ©diatement
  • TextEditingController : Permet de contrĂ´ler et initialiser le contenu des TextField
Vérifier si une clé existe :
Vous pouvez vérifier si une clé existe avant de la récupérer :
bool exists = prefs.containsKey('username');
if (exists) {
  String username = prefs.getString('username')!;
  print('Username trouvé: $username');
} else {
  print('La clé username n\'existe pas');
}
Récupérer toutes les clés :
Vous pouvez obtenir toutes les clés stockées :
Set<String> keys = prefs.getKeys();
print('Clés stockées: $keys');
Important :
Comme les méthodes get* peuvent retourner null, utilisez toujours l'opérateur ?? pour fournir une valeur par défaut. Cela évite les erreurs si la clé n'existe pas encore.

5.1.5 – Supprimer et modifier des données

Vous pouvez modifier ou supprimer des données stockées dans SharedPreferences. Pour modifier, utilisez simplement set* avec la même clé. Pour supprimer, utilisez remove() ou clear().

✏️ Modifier une valeur

Pour modifier une valeur existante, il suffit d'utiliser la même méthode set* avec la même clé. La valeur sera automatiquement remplacée.

📝 Syntaxe

// Modifier une valeur existante
// Si la clé existe déjà, la valeur sera remplacée
await prefs.setString('username', 'new_username');
await prefs.setInt('score', 1500); // Remplace l'ancien score

Analysons cette syntaxe :

  • setString('username', 'new_username') : Remplace la valeur de la clĂ© 'username'
  • Si la clĂ© n'existe pas, elle sera créée
  • Si la clĂ© existe, sa valeur sera remplacĂ©e

🗑️ Supprimer une clé

Pour supprimer une clé spécifique, utilisez la méthode remove() :

// Supprimer une clé spécifique
bool success = await prefs.remove('username');
if (success) {
  print('Clé supprimée avec succès');
} else {
  print('Erreur lors de la suppression');
}

🧹 Supprimer toutes les données

Pour supprimer toutes les données stockées, utilisez la méthode clear() :

// Supprimer toutes les données
bool success = await prefs.clear();
if (success) {
  print('Toutes les données ont été supprimées');
} else {
  print('Erreur lors de la suppression');
}
⚠️ Attention
La méthode clear() supprime toutes les données. Utilisez-la avec précaution, par exemple lors d'une déconnexion utilisateur ou d'une réinitialisation de l'application.

🧪 Exemple : Modifier et supprimer des préférences

Voici un exemple complet qui montre comment modifier et supprimer des préférences :

Exemple SharedPreferences Flutter
Exemple SharedPreferences Flutter avec modification et suppression des données.
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main() {
  runApp(const MonApp());
}

class MonApp extends StatelessWidget {
  const MonApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: const MaPage(),
    );
  }
}

class MaPage extends StatefulWidget {
  const MaPage({super.key});

  @override
  State<MaPage> createState() => _MaPageState();
}

class _MaPageState extends State<MaPage> {
  int score = 0;

  @override
  void initState() {
    super.initState();
    chargerScore();
  }

  Future<void> chargerScore() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    setState(() {
      score = prefs.getInt('score') ?? 0;
    });
  }

  Future<void> augmenterScore() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    
    // Récupérer le score actuel
    int scoreActuel = prefs.getInt('score') ?? 0;
    
    // Modifier le score (augmenter de 10)
    await prefs.setInt('score', scoreActuel + 10);
    
    // Recharger l'affichage
    chargerScore();
  }

  Future<void> supprimerScore() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    
    // Supprimer la clé 'score'
    await prefs.remove('score');
    
    // Recharger l'affichage
    chargerScore();
  }

  Future<void> reinitialiserTout() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    
    // Supprimer toutes les données
    await prefs.clear();
    
    // Recharger l'affichage
    chargerScore();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Modifier et supprimer'),
      ),
      body: SafeArea(
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Column(
            children: [
              Text(
                'Score actuel : $score',
                style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
              ),
              const SizedBox(height: 24),
              ElevatedButton(
                onPressed: augmenterScore,
                child: const Text('Augmenter le score (+10)'),
              ),
              const SizedBox(height: 16),
              ElevatedButton(
                onPressed: supprimerScore,
                style: ElevatedButton.styleFrom(
                  backgroundColor: Colors.orange,
                ),
                child: const Text('Supprimer le score'),
              ),
              const SizedBox(height: 16),
              ElevatedButton(
                onPressed: reinitialiserTout,
                style: ElevatedButton.styleFrom(
                  backgroundColor: Colors.red,
                ),
                child: const Text('Réinitialiser tout'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Dans cet exemple :

  • Le score est chargĂ© au dĂ©marrage
  • Le bouton "Augmenter le score" modifie la valeur existante
  • Le bouton "Supprimer le score" supprime uniquement la clĂ© 'score'
  • Le bouton "RĂ©initialiser tout" supprime toutes les donnĂ©es
Vérifier avant de supprimer :
Il est recommandé de vérifier si une clé existe avant de la supprimer :
if (prefs.containsKey('username')) {
  await prefs.remove('username');
  print('Username supprimé');
} else {
  print('La clé username n\'existe pas');
}
đź’ˇ Bonne pratique
Pour modifier une valeur, vous n'avez pas besoin de la supprimer d'abord. Utilisez directement set* avec la nouvelle valeur. La suppression n'est nécessaire que si vous voulez vraiment retirer une clé.

5.1.6 – Cas d'utilisation et limites

✅ Cas d'utilisation idéaux

1. Préférences utilisateur

SharedPreferences est parfait pour stocker les préférences de l'utilisateur :

// Exemple : Gestion du thème
Future<void> saveTheme(bool isDark) async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  await prefs.setBool('isDarkMode', isDark);
}

Future<bool> loadTheme() async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  return prefs.getBool('isDarkMode') ?? false;
}

2. Paramètres de l'application

Stocker des paramètres comme la langue, le volume, etc. :

// Exemple : Paramètres de langue et volume
Future<void> saveSettings(String language, double volume) async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  await prefs.setString('language', language);
  await prefs.setDouble('volume', volume);
}

3. Compteurs et statistiques simples

Pour suivre des compteurs ou des statistiques simples :

// Exemple : Compter les ouvertures de l'application
Future<void> incrementAppOpens() async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  int opens = prefs.getInt('appOpens') ?? 0;
  await prefs.setInt('appOpens', opens + 1);
}

4. Données de session non sensibles

Pour stocker des données de session simples (mais pas de mots de passe ou tokens sensibles) :

// Exemple : Nom d'utilisateur (non sensible)
Future<void> saveUsername(String username) async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  await prefs.setString('username', username);
}

❌ Limites et cas à éviter

1. Données sensibles

⚠️ Ne jamais utiliser SharedPreferences pour :
  • Mots de passe
  • Tokens d'authentification sensibles
  • NumĂ©ros de carte bancaire
  • Toute donnĂ©e personnelle sensible
Pour ces cas, utilisez flutter_secure_storage (voir section 5.2).

2. Grandes quantités de données

SharedPreferences n'est pas adapté pour stocker beaucoup de données :

  • Plus de 100-200 clĂ©s : les performances peuvent se dĂ©grader
  • DonnĂ©es volumineuses : chaque clĂ© ne devrait pas dĂ©passer quelques KB
  • DonnĂ©es frĂ©quemment modifiĂ©es : chaque modification Ă©crit sur le disque

3. Données relationnelles

Si vous avez besoin de relations entre données, utilisez une base de données :

Exemple : Ne pas utiliser SharedPreferences pour :
  • Liste d'utilisateurs avec relations (utilisateur → commandes → produits)
  • DonnĂ©es nĂ©cessitant des requĂŞtes complexes
  • DonnĂ©es nĂ©cessitant des jointures
Utilisez plutĂ´t SQLite (voir section 5.3).

4. Données nécessitant des requêtes

SharedPreferences ne permet pas de faire des recherches ou filtres :

  • Pas de recherche par valeur (seulement par clĂ©)
  • Pas de tri
  • Pas de filtrage

📊 Tableau comparatif

Critère
SharedPreferences
SQLite
Secure Storage
Types de données
Primitifs uniquement
Relations complexes
String uniquement
Volume de données
Petit (< 200 clés)
Grand (illimité)
Petit (données sensibles)
Sécurité
Non chiffré
Non chiffré
Chiffré
RequĂŞtes
Non
Oui (SQL)
Non
Simplicité
✓✓✓
âś“
✓✓

Légende : ✓✓✓ Excellent | ✓✓ Très bon | ✓ Bon | ✗ Faible

🤔 Quand choisir SharedPreferences ?

âś… Utilisez SharedPreferences si :

  • Vous avez besoin de stocker moins de 100-200 clĂ©s
  • Vous stockez des types primitifs (String, int, bool, double)
  • Vous n'avez pas besoin de requĂŞtes complexes
  • Les donnĂ©es ne sont pas sensibles
  • Vous voulez une solution simple et rapide
  • Vous stockez des prĂ©fĂ©rences utilisateur

❌ Utilisez une autre solution si :

  • Vous avez des donnĂ©es sensibles (utilisez Secure Storage)
  • Vous avez beaucoup de donnĂ©es (utilisez SQLite)
  • Vous avez besoin de requĂŞtes complexes (utilisez SQLite)
  • Vous avez des relations entre donnĂ©es (utilisez SQLite)
  • Vous stockez des objets complexes (utilisez SQLite ou Hive)
💡 Règle générale
Si vous hésitez entre SharedPreferences et une autre solution, posez-vous ces questions :
  1. Est-ce que j'ai moins de 200 clés ? → SharedPreferences
  2. Est-ce que les données sont sensibles ? → Secure Storage
  3. Est-ce que j'ai besoin de requêtes ? → SQLite
  4. Est-ce que j'ai des objets complexes ? → SQLite ou Hive
Exercice pratique :
Maintenant que vous maîtrisez SharedPreferences, mettez vos connaissances en pratique avec l'exercice ci-dessous ! Vous allez créer une page de paramètres complète avec persistance des données.

🎯 Exercice pratique

Objectif : Créer une page de paramètres complète avec persistance des données en utilisant SharedPreferences. L'application doit permettre de configurer l'apparence (mode sombre, thème de couleur), les notifications (activation et types), la langue et la taille de police. Toutes les modifications doivent être automatiquement sauvegardées et restaurées au redémarrage de l'application.

Interface de paramètres à reproduire
Interface à reproduire : Créez cette page de paramètres avec persistance des données en utilisant SharedPreferences.

📝 Instructions :

  1. Identifiez les défis : Observez l'interface et notez les défis techniques (par exemple : "Comment charger les paramètres au démarrage ?", "Comment sauvegarder automatiquement chaque modification ?", "Comment gérer le mode sombre avec SharedPreferences ?", etc.)
  2. Notez vos solutions : Avant de regarder le code, essayez de noter comment vous résoudriez chaque défi avec SharedPreferences (chargement dans initState(), sauvegarde dans onChanged, etc.)
  3. Comparez avec les solutions : Cliquez sur "Afficher le code" ci-dessous pour voir les solutions proposées et comparer avec vos notes. Analysez comment chaque paramètre est chargé et sauvegardé.
Points clés de l'exercice :
  • Chargement au dĂ©marrage : _chargerParametres() est appelĂ© dans initState() pour restaurer tous les paramètres sauvegardĂ©s
  • Sauvegarde automatique : Chaque modification (Switch, Radio, Checkbox, Dropdown) appelle immĂ©diatement _sauvegarder() pour persister la valeur
  • Fonction gĂ©nĂ©rique : _sauvegarder() dĂ©tecte automatiquement le type (bool ou String) et utilise la mĂ©thode appropriĂ©e
  • RĂ©initialisation : Le bouton "RĂ©initialiser" utilise clear() pour supprimer toutes les donnĂ©es, puis recharge les valeurs par dĂ©faut
  • Mode sombre dynamique : Le mode sombre change immĂ©diatement l'apparence de l'application et est sauvegardĂ© pour ĂŞtre restaurĂ© au prochain dĂ©marrage