Belajar menyimpan data di perangkat: SharedPreferences, JSON, Serialization, Hive, dan SQLite — sampai membangun Aplikasi Catatan Harian.
Gunakan tombol ◀ ▶ atau panah keyboard untuk navigasi
Setelah mempelajari bab ini, kamu akan mampu:
Menyimpan data sederhana dengan SharedPreferences agar tidak hilang saat aplikasi ditutup.
Mengubah objek Dart menjadi JSON dan sebaliknya (serialization & deserialization).
Mengenal database lokal Hive & SQLite serta kapan memakai masing-masing.
Di BAB 9 kamu belajar State Management — mengelola data selama aplikasi berjalan. Tapi ada satu masalah…
Data disimpan di memori (RAM). Bisa berubah secara reaktif lewat setStateProvider.
Begitu aplikasi ditutup atau HP restart, semua state hilang! Data di RAM bersifat sementara.
Kita simpan data ke penyimpanan permanen (disk) agar tetap ada walau aplikasi ditutup. Inilah persistence.
💡 Analogi: State = catatan di papan tulis (terhapus saat kelas bubar). Local Storage = catatan di buku tulis (tetap ada besok).
Local Storage adalah penyimpanan data di dalam perangkat (HP) itu sendiri, tanpa perlu internet/server.
Bayangkan laci meja belajarmu. Kamu bisa menaruh (simpan) buku ke dalam laci, lalu mengambilnya lagi kapan pun. Laci tetap menyimpan isinya walau kamu pergi sekolah. Local Storage bekerja persis seperti laci itu untuk data aplikasi.
Klik untuk "membuka laci" — seperti membaca/menyimpan data ke storage.
SharedPreferences menyimpan data sederhana berupa pasangan key–value (kunci–nilai). Cocok untuk: nama user, skor, tema gelap/terang, status login.
Seperti catatan tempel (sticky note) di pintu kulkas. Setiap catatan punya label (key) dan isi (value). Mau tahu "belanja apa?" → cari note berlabel belanja. Praktis untuk info kecil, tapi tidak untuk data besar & rumit.
Tipe data yang didukung: StringintdoubleboolList<String>
Setiap note = satu key : value
import 'package:shared_preferences/shared_preferences.dart';
// MENYIMPAN data (set)
Future<void> simpanNama(String nama) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('nama', nama); // key : value
}
// MEMBACA data (get)
Future<String> bacaNama() async {
final prefs = await SharedPreferences.getInstance();
// jika belum ada, beri nilai default 'Tamu'
return prefs.getString('nama') ?? 'Tamu';
}
// MENGHAPUS data
Future<void> hapusNama() async {
final prefs = await SharedPreferences.getInstance();
await prefs.remove('nama');
}
💡 Di browser kita pakai localStorage sebagai analogi SharedPreferences di Flutter — konsepnya sama: key–value yang persisten.
JSON (JavaScript Object Notation) adalah format teks untuk menyusun data secara terstruktur, agar mudah disimpan & dikirim.
JSON ibarat surat dalam amplop yang rapi. Isinya ditulis dengan format baku: ada nama bagian (key) dan isinya (value). Karena formatnya standar, siapa pun (atau aplikasi apa pun) bisa membaca isi surat itu tanpa bingung. Data dikemas jadi teks → mudah dikirim & disimpan.
{ }[ ]"key": valueSurat terstruktur yang bisa dibaca aplikasi mana pun
{
"id": 1,
"judul": "Belajar Flutter",
"isi": "Hari ini belajar JSON",
"selesai": false,
"tags": ["sekolah", "coding"],
"penulis": {
"nama": "Sahil",
"kelas": "10 RPL"
}
}
🔢 Number → "id": 1 (tanpa tanda kutip)
🔤 String → "judul": "Belajar" (pakai kutip ganda)
✅ Boolean → "selesai": false
📋 Array → "tags": [...] (daftar nilai)
📦 Object → "penulis": {...} (objek bersarang)
Serialization = mengubah objek Dart menjadi teks JSON, supaya bisa disimpan atau dikirim.
class Catatan {
final String judul;
final bool selesai;
Catatan(this.judul, this.selesai);
// Object ➜ Map ➜ JSON String
Map<String, dynamic> toJson() => {
'judul': judul,
'selesai': selesai,
};
}
📌 Mengapa perlu? Storage (file/SharedPrefs) hanya bisa menyimpan teks, bukan objek Dart langsung. Maka objek "diterjemahkan" dulu jadi teks JSON.
🔁 Alur: Object Dart → toJson() jadi Map → jsonEncode() jadi String.
Deserialization = kebalikannya. Mengubah teks JSON kembali menjadi objek Dart agar bisa dipakai program.
class Catatan {
final String judul;
final bool selesai;
Catatan(this.judul, this.selesai);
// JSON Map ➜ Object Dart (named constructor)
factory Catatan.fromJson(Map<String, dynamic> json) {
return Catatan(
json['judul'] as String,
json['selesai'] as bool,
);
}
}
📌 Kapan dipakai? Saat membaca data dari storage: teks JSON dibaca → diubah jadi objek → ditampilkan di UI.
🔁 Alur: String → jsonDecode() jadi Map → fromJson() jadi Object Dart.
import 'dart:convert';
void main() {
// 1. Buat objek
final c = Catatan('Belajar JSON', false);
// 2. SERIALIZE: Object ➜ JSON String
String jsonStr = jsonEncode(c.toJson());
print(jsonStr); // {"judul":"Belajar JSON","selesai":false}
// 3. DESERIALIZE: JSON String ➜ Object
Map<String, dynamic> map = jsonDecode(jsonStr);
Catatan c2 = Catatan.fromJson(map);
print(c2.judul); // Belajar JSON
}
Hive adalah database lokal NoSQL yang sangat cepat & ringan untuk Flutter. Data disimpan dalam Box (mirip kotak/wadah).
Bayangkan sarang lebah (hive). Setiap sel heksagonal menyimpan madu di tempatnya masing-masing, rapi dan cepat diambil. Hive bekerja begitu: tiap data ditaruh di "sel" dengan kunci, dan bisa diambil super cepat tanpa query rumit.
Tiap sel = satu data dalam Box
import 'package:hive_flutter/hive_flutter.dart';
void main() async {
// 1. Inisialisasi Hive
await Hive.initFlutter();
// 2. Buka sebuah Box (wadah penyimpanan)
var box = await Hive.openBox('catatanBox');
runApp(MyApp());
}
var box = Hive.box('catatanBox');
// CREATE / UPDATE — simpan data
box.put('judul', 'Belajar Hive');
box.put('selesai', false);
// READ — ambil data
String judul = box.get('judul'); // 'Belajar Hive'
var x = box.get('kosong', defaultValue: '-');
// DELETE — hapus data
box.delete('judul');
// Ambil semua nilai
print(box.values.toList());
💡 box.put(key, value) = menaruh madu ke sel. box.get(key) = mengambilnya kembali.
SQLite adalah database relasional (berbasis tabel) yang tertanam di perangkat. Di Flutter dipakai lewat package sqflite. Datanya tersusun dalam tabel berisi baris & kolom, dan diakses dengan bahasa SQL.
Seperti lemari arsip kantor yang sangat terorganisir. Tiap laci punya label, tiap folder punya baris data dengan kolom rapi (nama, tanggal, isi). Saat butuh data tertentu, kamu bisa "memerintah" lemari: "ambil semua arsip yang selesai = true" — itulah SQL query.
Cocok untuk: data banyak & berelasi, butuh pencarian/filter kompleks.
Arahkan kursor ke laci → "tarik keluar" data
INSERT — tambah baris baru
SELECT — baca data
UPDATE — ubah data
DELETE — hapus data
final db = await openDatabase('catatan.db', version: 1,
onCreate: (db, v) => db.execute(
'CREATE TABLE catatan(id INTEGER PRIMARY KEY, judul TEXT, selesai INTEGER)'
));
// CREATE
await db.insert('catatan', {'judul': 'Belajar SQL', 'selesai': 0});
// READ
List<Map> data = await db.query('catatan');
// UPDATE
await db.update('catatan', {'selesai': 1}, where: 'id = ?', whereArgs: [1]);
// DELETE
await db.delete('catatan', where: 'id = ?', whereArgs: [1]);
| Aspek | SharedPreferences | Hive | SQLite |
|---|---|---|---|
| Jenis | Key–Value sederhana | NoSQL (Box) | Relasional (Tabel + SQL) |
| Cocok untuk | Setting, skor, flag kecil | Objek/list, data sedang | Data banyak & berelasi |
| Kecepatan | ★★★☆☆ | ★★★★★ | ★★★★☆ |
| Kerumitan | Sangat mudah | Mudah | Menengah (perlu SQL) |
🔑 Pakai SharedPreferences bila datanya kecil & sederhana, contoh: status dark mode.
🐝 Pakai Hive bila butuh cepat menyimpan objek/list tanpa query rumit.
🗄️ Pakai SQLite bila data banyak, perlu filter/relasi & pencarian kompleks.
Kita akan membangun aplikasi Catatan Harian yang menyimpan catatan secara permanen menggunakan Hive.
class Catatan {
String judul;
bool selesai;
Catatan({required this.judul, this.selesai = false});
Map<String, dynamic> toJson() =>
{'judul': judul, 'selesai': selesai};
factory Catatan.fromJson(Map<String, dynamic> j) =>
Catatan(judul: j['judul'], selesai: j['selesai']);
}
class HiveStorage {
final box = Hive.box('catatanBox');
// simpan list catatan (sudah di-serialize)
void simpan(List<Catatan> list) {
box.put('catatan',
list.map((c) => c.toJson()).toList());
}
// baca list catatan (deserialize)
List<Catatan> baca() {
final raw = box.get('catatan', defaultValue: []);
return (raw as List)
.map((j) => Catatan.fromJson(Map.from(j)))
.toList();
}
}
class CatatanPage extends StatefulWidget {
@override
State<CatatanPage> createState() => _CatatanPageState();
}
class _CatatanPageState extends State<CatatanPage> {
final storage = HiveStorage();
List<Catatan> catatan = [];
@override
void initState() {
super.initState();
catatan = storage.baca(); // muat dari Hive
}
void tambah(String judul) {
setState(() => catatan.add(Catatan(judul: judul)));
storage.simpan(catatan); // simpan permanen
}
void hapus(int i) {
setState(() => catatan.removeAt(i));
storage.simpan(catatan);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Catatan Harian')),
body: ListView.builder(
itemCount: catatan.length,
itemBuilder: (_, i) => ListTile(
title: Text(catatan[i].judul),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () => hapus(i),
),
),
),
);
}
}
Bagaimana data mengalir saat user menambah satu catatan:
User mengetik judul & menekan tombol ➕
Object Catatan → toJson() → Map
box.put() menyimpan ke Hive (disk)
box.get() + fromJson() → Object
setState() render ulang ListView
Klik tiap node untuk mengingat poin utamanya.
1. Method yang benar untuk menyimpan String di SharedPreferences adalah…
2. Mengubah Object Dart menjadi JSON String disebut…
3. Fungsi jsonDecode() dipakai untuk…
✍️ Soal Essay: Jelaskan dengan kata-katamu sendiri perbedaan antara State (BAB 9) dan Local Storage (BAB 10). Berikan satu contoh kapan masing-masing dipakai.
Lengkapi scaffolding di bawah ini. Isi bagian // TODO agar fungsi CRUD bekerja.
final box = Hive.box('tugasBox');
// TODO 1: simpan tugas baru dengan key 'tugas1'
// _______________________________________
// TODO 2: baca tugas1, default '(kosong)'
String t = // ___________________________
// TODO 3: ubah nilai tugas1
// _______________________________________
// TODO 4: hapus tugas1
// _______________________________________
🎯 Kriteria sukses: keempat operasi CRUD (Create, Read, Update, Delete) berjalan tanpa error & data tersimpan setelah app di-restart.
🎯 Buat Aplikasi Catatan Harian versimu sendiri menggunakan SharedPreferences atau Hive.
| Kriteria | Bobot |
|---|---|
| Fungsi CRUD berjalan benar | 40% |
| Data persisten (storage benar) | 25% |
| Serialization/Deserialization rapi | 15% |
| Tampilan UI & kerapian kode | 20% |
🏆 Bonus (poin tambahan): tambahkan fitur tandai "selesai", pencarian catatan, atau pilih Hive vs SQLite dengan alasannya.
— SELAMAT BELAJAR! BAB 10 SELESAI 🎉 —