Setelah mempelajari REST API dan Pengolahan Data pada Level 8, Anda sudah memahami bagaimana aplikasi Flutter mengambil dan mengirim data melalui server.
Namun, aplikasi modern tidak selalu bergantung pada internet. Ada banyak situasi ketika aplikasi perlu menyimpan data langsung di perangkat pengguna.
Misalnya:
- preferensi tema aplikasi,
- status login tertentu,
- pengaturan pengguna,
- data favorit,
- draft formulir,
- daftar tugas,
- cache data,
- riwayat transaksi,
- data yang harus tetap tersedia ketika offline.
Di sinilah konsep database dan local storage Flutter menjadi penting.
Flutter menyediakan berbagai pendekatan untuk persistence atau penyimpanan data. Dokumentasi resminya membagi kebutuhan persistence antara lain menjadi key-value storage, file storage, dan database SQLite.
Untuk data sederhana, Anda dapat menggunakan key-value storage seperti shared_preferences. Untuk data yang lebih kompleks dan membutuhkan query, relasi, serta operasi CRUD, SQLite dapat menjadi pilihan yang lebih tepat.
Pada Level 9 tentang database Flutter ini, Anda akan mempelajari:
Local Storage
↓
Key-Value
↓
File Storage
↓
SQLite Database
↓
CRUD
↓
Repository
↓
Offline Data
Tujuannya bukan sekadar mengetahui cara menyimpan data, tetapi memahami kapan harus menggunakan masing-masing metode penyimpanan.
Database Flutter SQLite ini merupakan materi pembelajaran Level 9 dari Roadmap Belajar Flutter dari Nol Sampai Siap Kerja yang dibahas pada situs Raja Putra Media.
Apa Itu Local Storage?
Local storage adalah mekanisme untuk menyimpan data secara lokal pada perangkat tempat aplikasi berjalan.
Berbeda dengan REST API pada Level 8 yang biasanya berkomunikasi dengan server, local storage memungkinkan aplikasi menyimpan data tanpa harus selalu melakukan request ke internet.
Gambaran sederhananya:
REST API
Flutter
↓
Internet
↓
Server
↓
Database Server
Sedangkan local storage:
Flutter
↓
Local Storage
↓
Perangkat Pengguna
Karena data disimpan di perangkat, aplikasi dapat membaca data tersebut kembali pada saat aplikasi dibuka.
Konsep inilah yang disebut persistence.
Apa Itu Data Persistence?
Persistence berarti data tetap tersedia setelah aplikasi ditutup atau dijalankan kembali.
Misalnya aplikasi memiliki counter:
Nilai: 10
Jika nilai hanya disimpan dalam state:
Aplikasi ditutup
↓
State hilang
↓
Aplikasi dibuka
↓
Nilai kembali ke 0
Tetapi jika nilai disimpan secara persistent:
Nilai: 10
↓
Disimpan ke perangkat
↓
Aplikasi ditutup
↓
Aplikasi dibuka kembali
↓
Nilai: 10
Inilah perbedaan antara state sementara dan persistent storage.
Jenis Penyimpanan Data di Flutter
Secara sederhana, Anda dapat membagi penyimpanan lokal menjadi tiga kategori utama:
| Metode | Cocok Untuk |
|---|---|
| Key-value storage | Setting sederhana |
| File storage | File atau data berbentuk dokumen |
| SQLite | Data terstruktur dan kompleks |
Flutter menyediakan cookbook resmi untuk ketiga pendekatan tersebut. Mari kita bahas satu per satu.
1. Key-Value Storage
Key-value storage menyimpan data dalam pasangan:
key → value
Contohnya:
theme → dark
language → id
counter → 10
isFirstLaunch → false
Pendekatan ini cocok untuk data sederhana.
Contoh penggunaan:
- dark mode,
- bahasa aplikasi,
- setting pengguna,
- flag tertentu,
- nilai sederhana,
- preferensi aplikasi.
Salah satu package yang umum digunakan adalah:
shared_preferences
Dokumentasi Flutter menggunakan package tersebut untuk menyimpan data key-value secara persistent.
Mengenal shared_preferences
Tambahkan package:
flutter pub add shared_preferences
Package ini dapat menyimpan tipe data sederhana seperti:
intdoubleboolStringList<String>
Dokumentasi package saat ini juga menyediakan tiga API: SharedPreferences, SharedPreferencesAsync, dan SharedPreferencesWithCache. Untuk kode baru, dokumentasi package merekomendasikan API yang lebih baru seperti SharedPreferencesAsync atau SharedPreferencesWithCache; SharedPreferences merupakan API legacy.
Untuk pemula, konsep utamanya tetap sama:
Save
↓
Key + Value
↓
Read
↓
Update
↓
Remove
Menyimpan Data Sederhana
Dengan API modern SharedPreferencesAsync, contoh sederhana:
import 'package:shared_preferences/shared_preferences.dart';
final prefs = SharedPreferencesAsync();
await prefs.setString(
'username',
'Budi',
);
Untuk angka:
await prefs.setInt(
'counter',
10,
);
Boolean:
await prefs.setBool(
'darkMode',
true,
);
Membaca Data
Data yang telah disimpan dapat dibaca kembali.
final prefs = SharedPreferencesAsync();
final username = await prefs.getString(
'username',
);
Untuk integer:
final counter = await prefs.getInt(
'counter',
);
Jika data belum tersedia, hasilnya dapat berupa null.
Karena itu, Anda dapat memberikan nilai default:
final counter =
await prefs.getInt('counter') ?? 0;
Konsep seperti ini sangat sering digunakan dalam aplikasi Flutter.
Menghapus Data
Untuk menghapus sebuah key:
await prefs.remove('username');
Dengan demikian:
setString()
getString()
remove()
sudah cukup untuk banyak kebutuhan sederhana.
Kapan Menggunakan shared_preferences?
Gunakan key-value storage ketika datanya sederhana.
Contohnya:
darkMode = true
language = "id"
onboardingCompleted = true
fontSize = 16
Jangan gunakan shared_preferences sebagai database utama untuk menyimpan ribuan produk, transaksi, atau data relasional.
Dokumentasi Flutter menyebutkan bahwa key-value storage ditujukan untuk koleksi key-value yang relatif kecil dan tidak dirancang untuk menyimpan data dalam jumlah besar.
2. File Storage
Selain key-value storage, Flutter juga dapat membaca dan menulis file ke perangkat.
Pendekatan ini cocok ketika aplikasi perlu menyimpan:
- file teks,
- JSON file,
- hasil export,
- dokumen,
- cache file,
- file yang perlu dibaca kembali.
Flutter menggunakan kombinasi path_provider dan dart:io dalam recipe resmi untuk membaca dan menulis file pada perangkat mobile dan desktop.
Contoh sederhananya:
import 'dart:io';
import 'package:path_provider/path_provider.dart';
Kemudian mendapatkan lokasi penyimpanan:
final directory =
await getApplicationDocumentsDirectory();
final file = File(
'${directory.path}/data.txt',
);
Menulis file:
await file.writeAsString(
'Hello Flutter',
);
Membaca:
final content =
await file.readAsString();
print(content);
Kapan Menggunakan File Storage?
File storage lebih cocok ketika yang ingin disimpan memang berbentuk file.
Misalnya aplikasi editor dokumen:
Flutter
↓
Document
↓
File
↓
Device
Atau aplikasi yang menyimpan data JSON:
JSON
↓
data.json
↓
Local Device
Namun, jika data memiliki banyak record, pencarian, filtering, sorting, relasi, dan CRUD kompleks, database biasanya lebih sesuai.
Apa Itu Database?
Database adalah sistem yang digunakan untuk menyimpan dan mengelola data secara terstruktur.
Misalnya aplikasi toko memiliki tabel:
products
dengan kolom:
id
name
price
stock
category
Contohnya:
| id | name | price | stock |
|---|---|---|---|
| 1 | Laptop | 12000000 | 5 |
| 2 | Mouse | 250000 | 20 |
| 3 | Keyboard | 750000 | 10 |
Database memungkinkan aplikasi melakukan:
Create
Read
Update
Delete
atau biasa disingkat: CRUD
Apa Itu SQLite?
SQLite adalah database SQL yang dapat disimpan langsung sebagai file pada perangkat.
Untuk Flutter, salah satu package yang populer untuk SQLite adalah:
sqflite
Dokumentasi Flutter menggunakan sqflite untuk contoh persistence menggunakan SQLite. Recipe tersebut menunjukkan proses membuka database, membuat tabel, insert, query, update, dan delete.
Package sqflite saat ini mendukung Android, iOS, dan macOS secara langsung. Untuk Linux dan Windows terdapat pendekatan sqflite_common_ffi, sedangkan dukungan web melalui implementasi FFI web masih bersifat eksperimental.
Mengapa Menggunakan SQLite?
SQLite cocok ketika aplikasi memiliki data yang lebih kompleks.
Misalnya:
Todo App
Inventory
Expense Tracker
Offline Notes
Product Catalog
Local Cart
SQLite memberikan kemampuan untuk:
- membuat tabel,
- menyimpan banyak record,
- melakukan query,
- filtering,
- sorting,
- update,
- delete,
- relasi antar tabel,
- transaksi.
Berbeda dengan key-value storage yang hanya cocok untuk data sederhana.
Menambahkan sqflite
Untuk project Flutter mobile sederhana:
flutter pub add sqflite path
Dokumentasi Flutter menggunakan sqflite dan path untuk contoh SQLite. Package path membantu membangun lokasi file database dengan cara yang lebih aman lintas platform.
Kemudian:
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
Membuka Database
Database harus dibuka sebelum digunakan.
Contoh:
final database = openDatabase(
join(
await getDatabasesPath(),
'app_database.db',
),
);
Dalam aplikasi Flutter, operasi tersebut dilakukan secara asynchronous.
Karena itu:
await
diperlukan.
Membuat Table
Misalnya kita membuat aplikasi Todo.
Struktur tabel:
todos
id
title
completed
SQL sederhananya:
CREATE TABLE todos(
id INTEGER PRIMARY KEY,
title TEXT,
completed INTEGER
)
Dalam Flutter:
final database = openDatabase(
join(
await getDatabasesPath(),
'app_database.db',
),
onCreate: (db, version) {
return db.execute(
'''
CREATE TABLE todos(
id INTEGER PRIMARY KEY,
title TEXT,
completed INTEGER
)
''',
);
},
version: 1,
);
Flutter menggunakan version database untuk membantu menangani perubahan schema dari waktu ke waktu.
Memahami Database Schema
Schema adalah struktur database.
Misalnya:
Database
│
└── todos
├── id
├── title
└── completed
Ketika aplikasi berkembang, schema mungkin berubah.
Versi pertama:
todos
- id
- title
Versi kedua:
todos
- id
- title
- completed
Versi ketiga:
todos
- id
- title
- completed
- created_at
Perubahan tersebut disebut:
Database Migration
Migration penting ketika aplikasi sudah digunakan oleh pengguna dan struktur database harus berubah tanpa menghilangkan data yang sudah ada.
Membuat Model Dart
Sama seperti REST API Flutter: Panduan HTTP, JSON, dan Pengolahan Data pada Level 8, database juga sebaiknya memiliki model.
Contoh:
class Todo {
final int id;
final String title;
final bool completed;
Todo({
required this.id,
required this.title,
required this.completed,
});
}
Kemudian buat fungsi untuk mengubah model menjadi Map:
Map<String, Object?> toMap() {
return {
'id': id,
'title': title,
'completed': completed ? 1 : 0,
};
}
Mengapa bool diubah menjadi 0 atau 1?
SQLite memiliki tipe data yang berbeda dari Dart. sqflite mendokumentasikan tipe seperti INTEGER, REAL, TEXT, dan BLOB; bool dapat direpresentasikan menggunakan INTEGER dengan nilai 0 dan 1.
Insert Data
Sekarang kita dapat menyimpan Todo:
Future<void> insertTodo(
Todo todo,
) async {
final db = await database;
await db.insert(
'todos',
todo.toMap(),
);
}
Contoh penggunaannya:
await insertTodo(
Todo(
id: 1,
title: 'Belajar Flutter',
completed: false,
),
);
Read Data
Untuk membaca data:
Future<List<Map<String, Object?>>> getTodos()
async {
final db = await database;
return db.query('todos');
}
Hasil query berupa list.
Kemudian dapat diubah kembali menjadi model:
final rows = await getTodos();
final todos = rows.map((row) {
return Todo(
id: row['id'] as int,
title: row['title'] as String,
completed:
(row['completed'] as int) == 1,
);
}).toList();
Sekarang aplikasi memiliki:
List<Todo>
yang dapat digunakan oleh UI.
Update Data
Misalnya pengguna menyelesaikan sebuah Todo.
Gunakan:
await db.update(
'todos',
{
'completed': 1,
},
where: 'id = ?',
whereArgs: [todo.id],
);
Perhatikan penggunaan:
where: 'id = ?'
dan:
whereArgs: [todo.id]
Dokumentasi Flutter secara khusus menyarankan penggunaan whereArgs untuk parameter pada klausa where, bukan string interpolation, untuk membantu mencegah SQL injection.
Delete Data
Untuk menghapus:
await db.delete(
'todos',
where: 'id = ?',
whereArgs: [todo.id],
);
Dengan demikian, operasi database dasar sudah lengkap:
INSERT
↓
SELECT
↓
UPDATE
↓
DELETE
CRUD dalam Flutter
Mari sederhanakan:
| Operasi | SQLite | Tujuan |
|---|---|---|
| Create | insert() | Menambah data |
| Read | query() | Membaca data |
| Update | update() | Mengubah data |
| Delete | delete() | Menghapus data |
CRUD merupakan konsep yang sangat penting karena hampir semua aplikasi dengan database akan menggunakannya.
Query dengan WHERE
Tidak semua data harus diambil. Misalnya hanya ingin mengambil Todo yang belum selesai:
final result = await db.query(
'todos',
where: 'completed = ?',
whereArgs: [0],
);
Atau mencari berdasarkan ID:
final result = await db.query(
'todos',
where: 'id = ?',
whereArgs: [10],
);
Inilah salah satu keunggulan database dibandingkan penyimpanan key-value sederhana.
Sorting Data
Misalnya ingin mengurutkan data:
final result = await db.query(
'todos',
orderBy: 'id DESC',
);
Dengan demikian data terbaru dapat ditampilkan terlebih dahulu.
Limit Data
Database juga dapat membatasi jumlah hasil.
Misalnya:
final result = await db.query(
'todos',
limit: 10,
);
Konsep seperti ini akan berguna ketika jumlah data sudah besar.
Relasi Antar Tabel
Aplikasi nyata sering memiliki lebih dari satu tabel.
Misalnya aplikasi e-commerce:
users
products
categories
orders
order_items
Relasi dapat dibuat:
Category
↓
Products
↓
Order Items
↓
Orders
↓
User
Contoh sederhana:
CREATE TABLE categories(
id INTEGER PRIMARY KEY,
name TEXT
);
CREATE TABLE products(
id INTEGER PRIMARY KEY,
name TEXT,
category_id INTEGER,
FOREIGN KEY(category_id)
REFERENCES categories(id)
);
Flutter juga mendokumentasikan contoh hubungan antar tabel menggunakan foreign key.
Untuk pemula, Anda belum perlu menguasai seluruh konsep database relational sekaligus. Namun, memahami primary key dan foreign key akan sangat membantu ketika masuk ke project nyata.
Primary Key
Primary key adalah kolom yang digunakan sebagai identitas unik sebuah record.
Contohnya:
id
Data:
| id | name |
|---|---|
| 1 | Laptop |
| 2 | Mouse |
| 3 | Keyboard |
Tidak boleh ada dua record dengan ID yang sama jika id digunakan sebagai primary key.
Contoh:
id INTEGER PRIMARY KEY
Foreign Key
Foreign key digunakan untuk menghubungkan tabel.
Misalnya:
products
id
category_id
category_id dapat merujuk ke:
categories.id
Dengan demikian:
categories
↓
products
Konsep ini akan menjadi semakin penting ketika Anda membuat aplikasi yang memiliki banyak jenis data.
Database vs REST API
Setelah mempelajari Level 8 dan Level 9, Anda harus memahami bahwa REST API dan database lokal memiliki fungsi berbeda.
| REST API | Local Database |
|---|---|
| Berkomunikasi dengan server | Menyimpan data di perangkat |
| Membutuhkan jaringan untuk data online | Dapat digunakan tanpa internet |
| Data terpusat | Data lokal |
| Cocok untuk sinkronisasi | Cocok untuk offline/persistence |
| Backend biasanya mengelola database server | Aplikasi mengelola database lokal |
Dalam aplikasi nyata, keduanya sering digunakan bersama.
Contohnya:
REST API
↓
Server Data
↓
Flutter App
↙ ↘
State Local DB
↓
Offline
Menggabungkan REST API dengan Local Database
Inilah tahap yang lebih menarik. Misalnya aplikasi berita mengambil data:
Internet
↓
REST API
↓
Flutter
↓
SQLite
Ketika internet tersedia:
API
↓
Data baru
↓
Simpan SQLite
↓
Tampilkan
Ketika internet tidak tersedia:
SQLite
↓
Data terakhir
↓
Tampilkan
Pola seperti ini merupakan dasar dari aplikasi offline-capable atau offline-first.
Dokumentasi arsitektur Flutter juga membahas penyimpanan persisten dan offline-first sebagai bagian dari pola aplikasi yang lebih matang.
Local Database untuk Cache
Database lokal tidak selalu berarti sumber data utama. Kadang database lokal hanya digunakan sebagai cache.
Contohnya:
REST API
↓
Response
↓
SQLite
↓
Cache
Saat aplikasi dibuka:
Ada internet?
├── Ya → Ambil data API
│ ↓
│ Update cache
│
└── Tidak → Ambil cache lokal
Strategi ini dapat membuat aplikasi terasa lebih cepat dan lebih tahan terhadap koneksi internet yang tidak stabil.
Arsitektur Penyimpanan Data
Ketika aplikasi semakin besar, jangan menempatkan semua database logic di dalam widget.
Struktur sederhana:
lib/
├── models/
│ └── todo.dart
│
├── database/
│ └── database_service.dart
│
├── repositories/
│ └── todo_repository.dart
│
├── screens/
│ └── todo_page.dart
│
└── main.dart
Flutter saat ini juga memiliki panduan arsitektur persistence menggunakan pemisahan UI layer, domain/model layer, repository, dan database service.
Database Service
Database service bertanggung jawab terhadap operasi database.
Contohnya:
DatabaseService
│
├── open()
├── insert()
├── query()
├── update()
└── delete()
UI tidak perlu mengetahui bagaimana database dibuka.
Repository
Repository menjadi lapisan antara UI/application logic dengan sumber data.
Contohnya:
UI
↓
ViewModel / State
↓
Repository
↓
Database Service
↓
SQLite
Repository dapat menjadi tempat untuk menentukan sumber data.
Misalnya:
ProductRepository
↓
┌──────────────┐
│ │
API SQLite
Dengan pola tersebut, aplikasi dapat mengambil data dari API sekaligus menggunakan cache lokal.
Mengapa Tidak Langsung Menggunakan SQLite di Widget?
Bayangkan setiap screen memiliki:
openDatabase()
insert()
query()
update()
delete()
Jika aplikasi memiliki 20 screen, logic database dapat tersebar ke banyak tempat.
Akibatnya:
- sulit dirawat,
- sulit diuji,
- mudah terjadi duplikasi,
- perubahan database menjadi lebih rumit.
Lebih baik:
Widget
↓
Repository
↓
Database
Pemisahan ini akan menjadi dasar penting ketika Anda masuk ke Level 12 — Architecture.
Shared Preferences vs SQLite
Perbedaan paling penting:
| Kebutuhan | Pilihan |
|---|---|
| Dark mode | shared_preferences |
| Bahasa aplikasi | shared_preferences |
| Boolean sederhana | shared_preferences |
| User preference | shared_preferences |
| Banyak record | SQLite |
| Query data | SQLite |
| Relasi tabel | SQLite |
| CRUD kompleks | SQLite |
| Offline catalog | SQLite |
| Transaction | SQLite |
Jadi jangan berpikir bahwa SQLite selalu lebih baik.
Yang benar adalah:
Gunakan teknologi penyimpanan sesuai bentuk dan kebutuhan data.
File Storage vs Database
File storage juga memiliki tempatnya sendiri.
Gunakan file jika:
Data → File
Misalnya:
- PDF,
- TXT,
- JSON,
- dokumen,
- file export.
Gunakan database jika:
Data → Records
Misalnya:
- users,
- products,
- orders,
- transactions,
- todos.
Flutter menyediakan path_provider untuk membantu menemukan lokasi direktori file aplikasi pada platform yang didukung. Recipe resmi untuk file storage menggunakan dart:io bersama path_provider.
Jangan Menyimpan Password Secara Sembarangan
Ini merupakan bagian penting.
shared_preferences bukan tempat yang tepat untuk menyimpan data sensitif hanya karena praktis.
Misalnya:
password
private key
secret credential
sensitive token
Untuk kebutuhan keamanan tertentu, gunakan solusi secure storage yang memang dirancang untuk data sensitif. Pada tahap Level 11 nanti, pembahasan authentication dan penyimpanan credential dapat dilakukan lebih mendalam.
Untuk Level 9, prinsip yang perlu diingat adalah:
Local storage bukan berarti semua data aman untuk disimpan tanpa perlindungan.
Database Migration
Bayangkan versi pertama aplikasi memiliki:
todos
- id
- title
Kemudian versi baru membutuhkan:
todos
- id
- title
- completed
Database pengguna lama masih memiliki struktur versi pertama. Aplikasi perlu melakukan migration.
Contoh konsep:
version: 2,
onUpgrade: (db, oldVersion, newVersion) async {
if (oldVersion < 2) {
await db.execute(
'ALTER TABLE todos '
'ADD COLUMN completed INTEGER DEFAULT 0',
);
}
},
Migration harus dirancang dengan hati-hati agar data pengguna tidak hilang ketika aplikasi diperbarui.
Transaction
Ketika beberapa operasi database harus dianggap sebagai satu kesatuan, gunakan transaction.
Misalnya:
Buat Order
↓
Buat Order Item
↓
Kurangi Stock
Jika operasi kedua gagal, Anda mungkin tidak ingin operasi pertama tetap tersimpan.
Secara konsep:
BEGIN
↓
Operation 1
↓
Operation 2
↓
Operation 3
↓
COMMIT
Jika terjadi masalah:
ROLLBACK
Package sqflite juga menyediakan dukungan transaction dan batch. Untuk pemula, cukup pahami konsepnya terlebih dahulu.
Mini Project Level 9: Todo App dengan SQLite
Sekarang saatnya menggabungkan konsep.
Target:
Todo App
Fitur:
Create Todo
Read Todo
Update Todo
Delete Todo
Struktur:
lib/
├── models/
│ └── todo.dart
│
├── database/
│ └── database_service.dart
│
├── repositories/
│ └── todo_repository.dart
│
├── screens/
│ └── todo_page.dart
│
└── main.dart
Database:
todos
---------------------
id
title
completed
Flow:
User
↓
Todo Page
↓
Repository
↓
Database Service
↓
SQLite
Contoh Database Service
Contoh sederhana:
class DatabaseService {
Future<Database> open() async {
return openDatabase(
join(
await getDatabasesPath(),
'todo_database.db',
),
version: 1,
onCreate: (db, version) {
return db.execute(
'''
CREATE TABLE todos(
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT,
completed INTEGER
)
''',
);
},
);
}
}
Kemudian repository dapat menggunakan service tersebut.
Contoh Repository
class TodoRepository {
TodoRepository(
this.databaseService,
);
final DatabaseService databaseService;
Future<List<Todo>> getTodos() async {
final db =
await databaseService.open();
final rows = await db.query(
'todos',
orderBy: 'id DESC',
);
return rows.map((row) {
return Todo.fromMap(row);
}).toList();
}
}
Dengan struktur tersebut, UI tidak perlu berinteraksi langsung dengan SQL.
Menghubungkan Database dengan State Management
Level 7 sudah membahas state management. Sekarang database dapat menjadi sumber data bagi state.
Contohnya:
SQLite
↓
Repository
↓
State
↓
UI
Ketika user menambahkan Todo:
Button
↓
Repository.insert()
↓
SQLite
↓
Reload / Update State
↓
UI rebuild
Ini merupakan kombinasi konsep yang sangat penting.
Database dan Offline-First
Setelah memahami local storage, Anda mulai dapat membangun aplikasi yang tetap memiliki fungsi ketika internet terputus.
Contohnya:
Internet
│
▼
REST API
│
▼
Repository
│
▼
SQLite
│
▼
UI
Saat offline:
No Internet
X
│
▼
SQLite
│
▼
UI
Strategi offline-first akan menjadi semakin penting ketika Anda membangun aplikasi produksi.
Kesalahan Umum Saat Belajar Database Flutter
1. Menggunakan shared_preferences untuk Semua Data
Jangan gunakan key-value storage untuk database kompleks.
2. Tidak Membuat Model
Hindari menggunakan Map di seluruh aplikasi jika struktur data sudah jelas.
Lebih baik:
Database
↓
Map
↓
Model
↓
State
↓
UI
3. Menaruh SQL di Widget
UI sebaiknya tidak menjadi tempat utama untuk SQL query.
4. Tidak Memikirkan Migration
Begitu aplikasi digunakan pengguna, perubahan schema harus direncanakan.
5. Mengabaikan Error
Database operation juga dapat gagal.
Contohnya:
- database tidak dapat dibuka,
- schema bermasalah,
- query salah,
- data tidak sesuai,
- migration gagal.
6. Tidak Menggunakan Parameter Query
Hindari:
where: "id = ${todo.id}"
Gunakan:
where: 'id = ?',
whereArgs: [todo.id],
Selain lebih aman, pendekatan tersebut sesuai dengan pola yang ditunjukkan dokumentasi Flutter untuk query SQLite.
Latihan Level 9
Agar konsep benar-benar dipahami, kerjakan beberapa latihan berikut.
Latihan 1 — Counter Persistence
Buat counter yang tetap memiliki nilai terakhir setelah aplikasi ditutup.
Gunakan:
shared_preferences
Latihan 2 — Dark Mode
Buat fitur:
Light
Dark
Simpan pilihan pengguna secara lokal.
Latihan 3 — Todo SQLite
Buat:
Add Todo
Edit Todo
Delete Todo
Complete Todo
Gunakan SQLite.
Latihan 4 — Search Todo
Tambahkan pencarian:
Search
↓
SQLite query
↓
Filtered Result
Latihan 5 — REST API + SQLite
Gabungkan materi Level 8 dan Level 9:
REST API
↓
Fetch Data
↓
SQLite
↓
Local Cache
↓
UI
Kemudian buat aplikasi yang tetap dapat menampilkan data terakhir ketika internet tidak tersedia.
Checklist Level 9
Sebelum melanjutkan ke Level 10, pastikan Anda sudah memahami:
Local Storage
- Memahami local storage
- Memahami persistence
- Memahami key-value storage
- Mengetahui fungsi
shared_preferences - Dapat menyimpan String
- Dapat menyimpan Integer
- Dapat menyimpan Boolean
- Dapat membaca data
- Dapat menghapus data
File Storage
- Memahami file storage
- Mengetahui fungsi
path_provider - Mengetahui
dart:io - Dapat membaca file
- Dapat menulis file
SQLite
- Memahami SQLite
- Memahami table
- Memahami column
- Memahami row
- Memahami primary key
- Memahami foreign key
- Dapat membuat database
- Dapat membuat table
- Dapat melakukan INSERT
- Dapat melakukan SELECT
- Dapat melakukan UPDATE
- Dapat melakukan DELETE
- Memahami WHERE
- Memahami query parameter
- Memahami database version
- Memahami migration dasar
Architecture
- Memahami Database Service
- Memahami Repository
- Memahami Model
- Memahami hubungan Database → Repository → State → UI
Advanced Concept
- Memahami cache lokal
- Memahami offline data
- Mengetahui konsep offline-first
- Mengetahui transaction
- Memahami perbedaan API dan local database
Sampai Level 9, Anda sudah mempelajari sebagian besar fondasi teknis penting:
Flutter
↓
Dart
↓
Widgets
↓
Layout
↓
Navigation
↓
State Management
↓
REST API
↓
Database
↓
Local Storage
Namun, belajar teori saja belum cukup untuk menjadi Flutter Developer. Pada Level 10, Anda akan mulai menggabungkan berbagai kemampuan tersebut ke dalam sebuah real project Flutter.
Konsepnya akan berubah dari:
"Bagaimana cara menggunakan fitur Flutter?"
menjadi:
"Bagaimana cara membangun aplikasi Flutter?"
Anda akan mulai belajar menentukan:
- ide aplikasi,
- fitur,
- struktur project,
- UI flow,
- navigation,
- state management,
- REST API,
- database,
- validasi,
- error handling,
- dan pengembangan fitur secara bertahap.
Dengan kata lain, Level 10 menjadi titik penting untuk mengubah pengetahuan yang telah dipelajari dari Level 0–9 menjadi sebuah aplikasi yang benar-benar dapat digunakan.
Kesimpulan
Database dan local storage merupakan kemampuan penting bagi Flutter Developer karena aplikasi nyata tidak selalu bergantung pada data dari server.
Pada Level 9, Anda telah mempelajari tiga pendekatan utama:
Key-Value
↓
shared_preferences
File
↓
path_provider + dart:io
Database
↓
SQLite + sqflite
Gunakan key-value storage untuk data sederhana seperti preferensi aplikasi. Gunakan file storage ketika aplikasi perlu menyimpan file atau data berbasis file. Untuk data terstruktur yang membutuhkan query dan CRUD, gunakan database seperti SQLite. Flutter secara resmi menyediakan recipe untuk ketiga kebutuhan persistence tersebut.
Anda juga telah belajar:
CREATE
READ
UPDATE
DELETE
serta konsep:
Model
↓
Database Service
↓
Repository
↓
State
↓
UI
Struktur tersebut menjadi dasar yang sangat baik untuk aplikasi Flutter yang lebih besar. Yang tidak kalah penting adalah memahami hubungan antara Level 8 dan Level 9:
REST API
↓
Flutter
↓
Local Database
↓
Offline
Dengan kombinasi REST API dan local storage, aplikasi dapat mengambil data dari server sekaligus mempertahankan data tertentu di perangkat.
Setelah menguasai konsep ini, Anda sudah memiliki fondasi yang cukup untuk mulai membangun aplikasi Flutter yang lebih realistis.
Selanjutnya, kita masuk ke Level 10 — Real Project Flutter, yaitu tahap ketika seluruh kemampuan dari Level 0 sampai Level 9 mulai digabungkan menjadi sebuah project aplikasi yang lebih lengkap.
- belajar database Flutter
- belajar Flutter
- belajar Flutter dari nol
- belajar Flutter untuk pemula
- CRUD Flutter
- database Flutter
- database lokal Flutter
- database SQLite Flutter
- Flutter Developer
- Flutter offline storage
- local database Flutter
- local storage Flutter
- menyimpan data Flutter
- penyimpanan data Flutter
- penyimpanan lokal Flutter
- shared preferences Flutter
- shared_preferences Flutter
- SQL Flutter
- SQLite CRUD Flutter
- SQLite Flutter
- tutorial Flutter
Tinggalkan komentar