Terakhir diperbarui: 17 November 2025
Penulis: Habibie Ed Dien
Pada codelab ini, Anda akan mempelajari tentang persistensi data di Flutter beserta contoh penggunaannya. Cara kerja, manfaat, dan cara mengelola data JSON lebih lanjut.
Video berikut menjelaskan tentang persistensi data menggunakan Shared Preferences. Silakan simak dan pahami!
Setelah menyelesaikan codelab ini Anda akan mampu untuk:
path_providerBerikut merupakan sumber daya yang diperlukan untuk menyelesaikan praktikum ini:
Kebanyakan aplikasi, terutama yang berbasis bisnis, pasti membutuhkan operasi CRUD: Create, Read, Update, dan Delete data. Data dapat disimpan secara local atau remote. Tanpa peduli data itu akan disimpan di mana, pada beberapa kasus kita tetap membutuhkan data itu berbentuk JSON sebelum itu disimpan secara permanen. Sehingga kita perlu tau metode apa saja yang diperlukan untuk mengolah JSON di Dart dan Flutter. Hal ini akan sangat membantu pada beberapa teknologi yang mungkin Anda akan gunakan, seperti SQLite, Sembast, dan database Firebase. Semua itu membutuhkan proses pengiriman dan unduh data berupa JSON.
Selesaikan langkah-langkah praktikum berikut ini menggunakan editor Visual Studio Code (VS Code) atau Android Studio atau code editor lain kesukaan Anda. Jawablah di laporan praktikum Anda (ketik di README.md) pada setiap soal yang ada di beberapa langkah praktikum ini.
Buatlah sebuah project flutter baru dengan nama store_data_nama (beri nama panggilan Anda) di folder week-13/src/ repository GitHub Anda.
main.dartKetiklah kode seperti berikut ini.


assetsBuat folder baru assets di root project Anda
pizzalist.jsonLetakkan file ini di dalam folder assets, lalu salin data JSON berikut ke file tersebut.
[
{
"id": 1,
"pizzaName": "Margherita",
"description": "Pizza with tomato, fresh mozzarella and basil",
"price": 8.75,
"imageUrl": "images/margherita.png"
},
{
"id": 2,
"pizzaName": "Marinara",
"description": "Pizza with tomato, garlic and oregano",
"price": 7.50,
"imageUrl": "images/marinara.png"
},
{
"id": 3,
"pizzaName": "Napoli",
"description": "Pizza with tomato, garlic and anchovies",
"price": 9.50,
"imageUrl": "images/marinara.png"
},
{
"id": 4,
"pizzaName": "Carciofi",
"description": "Pizza with tomato, fresh mozzarella and artichokes",
"price": 8.80,
"imageUrl": "images/marinara.png"
},
{
"id": 5,
"pizzaName": "Bufala",
"description": "Pizza with tomato, buffalo mozzarella and basil",
"price": 12.50,
"imageUrl": "images/marinara.png"
}
]
Jika Anda ingin menggunakan data JSON yang lain, Anda dapat mengakses salah satu dari daftar API di tautan ini: https://github.com/public-apis/public-apis
pubspec.yamlTambahkan referensi folder assets ke file pubspec.yaml seperti berikut ini.

maint.dartBuatlah variabel seperti berikut ini class _MyHomePageState.

main.dartUntuk membaca isi dari file pizzalist.json di dalam class _MyHomePageState, tambahkan method readJsonFile seperti kode berikut untuk membaca file json.

Panggil method readJsonFile di initState

Kemudian tampilkan hasil JSON di body scaffold.

Jika kode sudah benar, seharusnya tampil seperti gambar berikut ini.

pizza.dartKita ingin mengubah data json tersebut dari String menjadi objek List. Maka perlu membuat file class baru di folder lib/model dengan nama file pizza.dart.
Ketik kode berikut pada file pizza.dart

constructor()Di dalam class Pizza definisikan constructor fromJson, yang mana akan mengambil data berupa Map sebagai parameter dan mengubah Map ke objek Pizza seperti kode berikut:

class _MyHomePageStateTambahkan kode jsonDecode seperti berikut.

Perhatikan pada bagian atas file bahwa telah berhasil impor kedua file berikut.

Anda telah berhasil mengimpor pustaka yang diperlukan dan melakukan decoding string JSON menjadi List pizzaMapList pada Langkah ini. Selanjutnya, kita akan mengonversi List Map tersebut menjadi List objek Dart (List<Pizza>).
Di dalam method readJsonFile(), setelah baris List pizzaMapList = jsonDecode(myString);, tambahkan kode berikut untuk mengonversi setiap Map di pizzaMapList menjadi objek Pizza dan menyimpannya ke myPizzas.

Hapus atau komentari setState yang menampilkan pizzaString dari Langkah 7. Kemudian, kembalikan myPizzas.

Perbarui signature method readJsonFile() untuk secara eksplisit menunjukkan bahwa ia mengembalikan Future yang berisi List.

Di dalam class _MyHomePageState, deklarasikan variabel state baru untuk menampung List objek Pizza.

Perbarui method initState() di _MyHomePageState untuk memanggil readJsonFile(). Karena readJsonFile() mengembalikan Future, gunakan .then() untuk mendapatkan hasilnya, dan perbarui state myPizzas.

Perbarui body dari Scaffold untuk menggunakan ListView.builder yang menampilkan pizzaName sebagai judul dan description sebagai subjudul dari setiap objek Pizza.
body: ListView.builder(
itemCount: myPizzas.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(myPizzas[index].pizzaName),
subtitle: Text(myPizzas[index].description),
);
},
));
}
Jalankan aplikasi. Sekarang, Anda akan melihat data pizza ditampilkan dalam daftar yang lebih terstruktur sebagai objek List Dart.

Di file pizza.dart, tambahkan method toJson() ke class Pizza. Method ini berfungsi untuk mengonversi objek Dart kembali menjadi Map (langkah pertama menuju JSON String).

Di main.dart, tambahkan fungsi convertToJSON di dalam _MyHomePageState untuk menggunakan jsonEncode (dari dart:convert) yang mengubah List objek Dart menjadi JSON String.

Di method readJsonFile(), tambahkan kode untuk memanggil convertToJSON dan mencetak hasilnya ke Debug Console sebelum mengembalikan myPizzas.
String json = convertToJSON(myPizzas);
print(json);
return myPizzas;
Jalankan aplikasi. Periksa Debug Console untuk melihat List objek Pizza telah berhasil dikonversi kembali menjadi JSON String.

Setelah Anda menyelesaikan praktikum 1, Anda dapat melanjutkan praktikum 2 ini. Selesaikan langkah-langkah praktikum berikut ini menggunakan editor Visual Studio Code (VS Code) atau Android Studio atau code editor lain kesukaan Anda. Jawablah di laporan praktikum Anda pada setiap soal yang ada di beberapa langkah praktikum ini.
Pada codelab ini, kita akan berfokus pada skema JSON yang tidak kompatibel dengan model yang telah kita buat sebelumnya. Kita akan membuat kode lebih tangguh dengan menangani type casting dan nilai null.
Anggaplah Anda telah mengganti file pizzalist.json dengan data yang tidak konsisten.
Jika ID pizza di JSON dikirim sebagai String (misalnya "id": "1" di JSON) sementara model Dart mengharapkan int, Anda akan melihat runtime error.

Di Pizza.fromJson (file pizza.dart), ganti cara mendapatkan nilai id menggunakan int.tryParse dan null coalescing operator (??) untuk memberikan nilai default 0 jika parsing gagal atau nilainya null. Tujuannya adalah memastikan nilai id selalu integer.

Jika Anda menjalankan ulang dan ada bidang yang hilang (misalnya imageUrl hilang), Anda mungkin mendapatkan error Null.

Tambahkan null coalescing operator (??) pada imageUrl untuk memberikan string kosong ('') jika nilai yang diterima adalah null. Lakukan hal yang sama untuk bidang String lainnya seperti pizzaName dan description jika perlu.


Untuk memastikan semua nilai yang digunakan sebagai String benar-benar String (bahkan jika mereka mungkin dikirim sebagai int atau tipe lain), gunakan toString().

Jika Anda menjalankan ulang, Anda mungkin menemukan error saat mengonversi String ke Double untuk bidang price.

Terapkan double.tryParse dengan null coalescing (?? 0) untuk bidang price, sama seperti yang Anda lakukan pada id.

Setelah mengimplementasikan semua perbaikan tipe data, aplikasi akan berjalan, tetapi mungkin menampilkan "null" di UI jika ada bidang yang hilang atau gagal diparsing (seperti pizzaName atau description).

Perbaiki masalah tampilan "null" dengan menambahkan operator ternary yang memeriksa apakah nilai null sebelum mengubahnya menjadi String. Jika null, berikan nilai pengganti yang ramah pengguna seperti 'No name' atau string kosong ('').

Jalankan aplikasi. Sekarang data yang tidak konsisten telah ditangani dengan baik, dan UI tidak menampilkan nilai null.
Pada praktikum 3 ini, Anda akan berfokus pada Catching common JSON errors, yaitu dengan mengganti string literals (nama kunci JSON) dengan konstanta untuk menghindari error yang sulit di-debug (kesalahan pengetikan).
Setelah Anda menyelesaikan praktikum 2, Anda dapat melanjutkan praktikum 3 ini. Selesaikan langkah-langkah praktikum berikut ini menggunakan editor Visual Studio Code (VS Code) atau Android Studio atau code editor lain kesukaan Anda. Jawablah di laporan praktikum Anda pada setiap soal yang ada di beberapa langkah praktikum ini.
pizza.dart dan Buat KonstantaDi bagian atas file pizza.dart, di luar class Pizza, deklarasikan konstanta untuk setiap kunci JSON.

Di constructor Pizza.fromJson, ganti semua string literal kunci JSON (misalnya 'id') dengan konstanta yang sesuai (keyId).

Perbarui juga method toJson() agar menggunakan konstanta yang sama.

Jalankan aplikasi. Tidak akan ada perubahan visual, tetapi kode Anda kini lebih safe dan maintainable.
Praktikum ini membahas menyimpan data sederhana dengan SharedPreferences. Kita akan menggunakan shared_preferences untuk menyimpan hitungan sederhana.
Setelah Anda menyelesaikan praktikum 3, Anda dapat melanjutkan praktikum 4 ini. Selesaikan langkah-langkah praktikum berikut ini menggunakan editor Visual Studio Code (VS Code) atau Android Studio atau code editor lain kesukaan Anda. Jawablah di laporan praktikum Anda pada setiap soal yang ada di beberapa langkah praktikum ini.
Di Terminal, tambahkan package shared_preferences.

Jalankan flutter pub get jika editor Anda tidak melakukannya secara otomatis.
Di file main.dart, tambahkan import untuk shared_preferences.

Di dalam class _MyHomePageState (atau State class yang Anda gunakan), deklarasikan variabel appCounter.

Buat method asinkron readAndWritePreference().

Di dalam method tersebut, dapatkan instance SharedPreferences. Perlu diingat bahwa ini adalah operasi asinkron, jadi gunakan await.

Baca nilai appCounter dari storage. Gunakan null coalescing (?? 0) untuk memastikan nilai default 0 jika data belum ada. Kemudian increment nilai tersebut.

Simpan nilai appCounter yang sudah di-increment kembali ke storage menggunakan prefs.setInt().

Panggil setState() untuk memperbarui UI dengan nilai baru appCounter.

Panggil readAndWritePreference() di initState() agar penghitung dibaca saat aplikasi pertama kali dibuka.

Ganti body Scaffold Anda dengan tata letak yang menampilkan hitungan dan tombol 'Reset counter'.

Aplikasi sekarang akan menampilkan "You have opened the app 1 times" (jika ini pembukaan pertama).

Tambahkan method asinkron deletePreference() yang berfungsi untuk menghapus data menggunakan prefs.clear().

Hubungkan deletePreference() ke tombol 'Reset counter'.

Jalankan aplikasi. Tombol reset sekarang akan berfungsi, menghapus semua pasangan kunci-nilai dan mereset hitungan.
Praktikum ini berfokus untuk mengakses file system menggunakan path_provider untuk menemukan direktori umum (documents dan temp) pada perangkat.
Setelah Anda menyelesaikan praktikum 4, Anda dapat melanjutkan praktikum 5 ini. Selesaikan langkah-langkah praktikum berikut ini menggunakan editor Visual Studio Code (VS Code) atau Android Studio atau code editor lain kesukaan Anda. Jawablah di laporan praktikum Anda pada setiap soal yang ada di beberapa langkah praktikum ini.
Tambahkan package path_provider melalui Terminal.

Di file main.dart, tambahkan import untuk path_provider.

Di State class Anda, tambahkan variabel untuk menyimpan jalur direktori dokumen dan temporer.

Buat method asinkron getPaths() yang menggunakan getApplicationDocumentsDirectory() dan getTemporaryDirectory() untuk mengambil jalur sistem file yang tepat, lalu perbarui state.

Panggil getPaths() di initState().
@override
void initState() {
super.initState();
getPaths();
}
Perbarui body Scaffold untuk menampilkan kedua jalur yang telah diambil.

Jalankan aplikasi. Anda akan melihat path absolut ke direktori dokumen dan cache aplikasi di perangkat Anda.

Praktikum ini melanjutkan dari Praktikum 5, berfokus pada akses file system untuk mengakses directories, menggunakan library dart:io untuk operasi file.
Setelah Anda menyelesaikan praktikum 5, Anda dapat melanjutkan praktikum 6 ini. Selesaikan langkah-langkah praktikum berikut ini menggunakan editor Visual Studio Code (VS Code) atau Android Studio atau code editor lain kesukaan Anda. Jawablah di laporan praktikum Anda pada setiap soal yang ada di beberapa langkah praktikum ini.
Di file main.dart, tambahkan import untuk pustaka dart:io.

Di State class, tambahkan variabel myFile (dengan modifier late) dan fileText untuk menyimpan konten yang akan dibaca.

Buat method asinkron writeFile() yang menggunakan myFile.writeAsString() untuk menulis konten ke file. Kata ‘Margherita, Capricciosa, Napoli' silakan Anda ganti dengan Nama Lengkap dan NIM Anda.
Future<bool> writeFile() async {
try {
await myFile.writeAsString('Margherita, Capricciosa, Napoli');
return true;
} catch (e) {
return false;
}
}
Perbarui initState(): setelah getPaths() selesai, inisialisasi myFile dengan jalur lengkap di direktori dokumen, dan panggil writeFile().

Buat method asinkron readFile() yang menggunakan myFile.readAsString() untuk membaca konten file dan memperbarui fileText melalui setState().

Di method build(), tambahkan ElevatedButton yang memanggil readFile() dan Text yang menampilkan fileText di bawahnya.


Jalankan aplikasi. Setelah menekan tombol 'Read File', konten yang ditulis (Margherita, Capricciosa, Napoli) akan ditampilkan atau sesuai nama dan NIM Anda.

Pada praktikum ini Anda akan praktik menggunakan secure storage untuk menyimpan data menggunakan package flutter_secure_storage untuk menyimpan data sensitif (seperti kata sandi) dengan aman.
Setelah Anda menyelesaikan praktikum 6, Anda dapat melanjutkan praktikum 7 ini. Selesaikan langkah-langkah praktikum berikut ini menggunakan editor Visual Studio Code (VS Code) atau Android Studio atau code editor lain kesukaan Anda. Jawablah di laporan praktikum Anda pada setiap soal yang ada di beberapa langkah praktikum ini.
Tambahkan package flutter_secure_storage melalui Terminal.

Di main.dart, impor package yang diperlukan.
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
Di State class (_MyHomePageState), tambahkan TextEditingController dan variabel untuk menyimpan kata sandi yang dibaca.
final pwdController = TextEditingController();
String myPass = '';
Di State class, inisialisasi FlutterSecureStorage dan tentukan kuncinya.

Buat method asinkron untuk menulis data dari pwdController ke secure storage.

Buat method asinkron untuk membaca data dari secure storage.

Perbarui method build() untuk menyertakan TextField dan dua ElevatedButton (Save Value dan Read Value). Hubungkan method save ke tombol Save Value.
// Di dalam body: Column children:
TextField(
controller: pwdController,
),
ElevatedButton(child: const Text('Save Value'), onPressed: () {
writeToSecureStorage();
}),
// ...
Hubungkan method read ke tombol Read Value, perbarui myPass dan UI melalui setState().

Jalankan aplikasi. Masukkan teks, simpan, lalu baca kembali. Teks tersebut seharusnya ditampilkan, menandakan data telah disimpan dan diambil dengan aman.

Selamat Anda telah menyelesaikan Codelab ini. Anda telah mempelajari terkait Persistensi Data dan contoh penggunaannya.
Pada codelab berikutnya, Anda akan mempelajari tentang Restful API.
Jangan sungkan jika Anda menemukan kesalahan pada codelab ini untuk merevisi atau sekedar melaporkan issue melalui tautan di pojok kiri bawah (Report a mistake).
Silakan cek beberapa sumber belajar lainnya...