Speichere Einstellungen und leichte Daten dauerhaft mit shared_preferences und kenne dabei die Grenzen bei Sicherheit und Datenmenge.
Diese Lektion in Kodokon öffnenshared_preferences ist ein Schlüssel/Wert-Speicher, der auf nativen Mechanismen aufsetzt (SharedPreferences unter Android, UserDefaults unter iOS). Seine Stärke: kleine Daten - gewähltes Theme, Onboarding gesehen, zuletzt aktiver Tab. Alles darüber hinaus verlangt ein anderes Werkzeug: eine sqflite- oder drift-Datenbank für große oder abfragbare Daten, flutter_secure_storage für alles Sensible. Die Datei wird komplett in den Arbeitsspeicher geladen: Sie ist weder verschlüsselt noch dafür gebaut zu wachsen.
flutter pub add shared_preferencesgetInstance() ist beim ersten Aufruf asynchron (Lesen der Datei) und liefert danach eine zwischengespeicherte Instanz: Die folgenden get*-Aufrufe sind synchron und werden aus dem Speicher bedient. Die set*-Aufrufe schreiben dagegen asynchron auf die Festplatte. In der Praxis: Streue keine Schlüssel-Strings über die ganze Anwendung, sondern zentralisiere sie in einem typisierten, injizierbaren und testbaren Wrapper.
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);
}Die API speichert nur primitive Typen: bool, int, double, String und List<String>. Für ein strukturiertes Objekt serialisierst du es nach JSON - deine toJson/fromJson aus der ersten Lektion kommen hier wieder zum Einsatz. Ein akzeptierter Kompromiss: Jedes Speichern schreibt den kompletten Wert neu und Abfragen sind nicht möglich. Perfekt für einen Entwurf, ungeeignet für einen Verlauf.
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?get*-Lesevorgänge nach dem ersten getInstance()?Futures zurück, auf die du jedes Mal warten musst.Draft-Objekt?jsonEncode nach JSON und speichere es über setString.prefs.setObject('draft', draft), das genau dafür gedacht ist.setStringList auf.