storagelokalpreferencesMahir4 mnt baca

SharedPreferences

Simpan data kecil persisten: tema, token, onboarding.

Kenapa SharedPreferences Ada: Masalah yang Diselesaikan

Hampir setiap aplikasi butuh menyimpan hal-hal kecil yang harus bertahan setelah aplikasi ditutup: pilihan dark mode, status onboarding ("sudah pernah dibuka?"), token login, atau bahasa yang dipilih. Membuat tabel database hanya untuk menyimpan satu boolean jelas berlebihan.

SharedPreferences menyelesaikan ini dengan penyimpanan key-value yang persisten dan super ringan: di Android ia memakai SharedPreferences XML, di iOS memakai NSUserDefaults. API-nya async tapi sederhana, dan baca tulisnya cukup cepat untuk data kecil.

Contoh Dasar

bash
flutter pub add shared_preferences
dart
final prefs = await SharedPreferences.getInstance();

// simpan:
await prefs.setBool('gelap', true);
await prefs.setString('token', 'abc123');
await prefs.setInt('buka_ke', 3);

// baca (dengan nilai default kalau key belum ada):
final gelap = prefs.getBool('gelap') ?? false;
final token = prefs.getString('token');

Perhatikan pola ??: getString mengembalikan null kalau key belum pernah disimpan, jadi selalu sediakan fallback.

Contoh Nyata: Service yang Rapi

Memanggil SharedPreferences.getInstance() di setiap widget itu berantakan dan rawan lupa await. Bungkus dalam satu service:

dart
class PengaturanService {
  PengaturanService._();
  static final PengaturanService instance = PengaturanService._();

  static const _keyGelap = 'pengaturan_gelap';
  static const _keyOnboarding = 'pengaturan_onboarding_selesai';

  SharedPreferences? _prefs;

  Future<void> init() async {
    _prefs ??= await SharedPreferences.getInstance();
  }

  bool get modeGelap => _prefs?.getBool(_keyGelap) ?? false;

  Future<void> setModeGelap(bool v) async {
    await _prefs?.setBool(_keyGelap, v);
  }

  bool get onboardingSelesai =>
      _prefs?.getBool(_keyOnboarding) ?? false;

  Future<void> tandaiOnboardingSelesai() async {
    await _prefs?.setBool(_keyOnboarding, true);
  }
}

// di main:
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await PengaturanService.instance.init();
  runApp(const MyApp());
}

Kunci disimpan sebagai konstanta privat supaya tidak ada typo key yang menyebabkan bug "data hilang" yang misterius.

Edge Case yang Perlu Diwaspadai

  • getInstance() itu async dan tidak murah. Panggil sekali di awal (seperti contoh di atas), jangan di setiap build.
  • Tipe data terbatas: hanya int, double, bool, String, dan List<String>. Butuh objek kompleks? Serialisasi ke JSON string dulu dengan jsonEncode.
  • Tidak ada enkripsi. Token login di sini bisa dibaca siapa pun yang punya akses ke file aplikasi. Untuk data sensitif pakai flutter_secure_storage.
  • Hati-hati dengan clear(): ia menghapus SEMUA key, termasuk yang dipakai package lain. Lebih aman remove() key milikmu satu per satu.
  • Key collision: beri prefix yang jelas (pengaturan_, cache_) supaya tidak tabrakan dengan key dari package lain.
  • reload(): di platform tertentu, perubahan dari luar (jarang terjadi) butuh prefs.reload() agar terbaca. Untuk pemakaian normal tidak diperlukan.

Kapan JANGAN Pakai SharedPreferences

  • Data besar atau banyak baris (daftar produk, riwayat transaksi): pakai sqflite atau database lokal lain.
  • Data sensitif (password, token refresh, PIN): pakai flutter_secure_storage yang terenkripsi.
  • Data yang harus sinkron antar device: SharedPreferences murni lokal. Butuh backend atau sinkronisasi cloud.
  • State sementara yang tidak perlu persisten (filter yang sedang dipilih, tab aktif): cukup state management biasa seperti Riverpod atau setState.

Catatan teknis: Setelah getInstance() pertama selesai, semua operasi baca (getBool, getString, dan kawan-kawan) sebenarnya sinkron dari cache di memori, jadi aman dipanggil di dalam build tanpa await. Yang tetap async hanya operasi tulis dan pemanggilan getInstance() pertama.

Tantangan

Ingat tema

Simpan pilihan dark mode ke SharedPreferences setiap toggle, dan muat saat app start agar pilihan tidak hilang.