1. Sebelum memulai
Pengantar
Dalam codelab ini, Anda akan meningkatkan pengalaman pengguna untuk aplikasi menggunakan cache offline. Banyak aplikasi mengandalkan data dari jaringan. Jika aplikasi Anda mengambil data dari server pada setiap peluncuran dan pengguna melihat layar pemuatan, ini bisa jadi merupakan pengalaman pengguna yang buruk sehingga pengguna meng-uninstal aplikasi Anda.
Saat pengguna meluncurkan aplikasi, mereka berharap aplikasi menampilkan data dengan cepat. Anda dapat mencapai sasaran ini dengan menerapkan cache offline. Pembuatan cache secara offline berarti aplikasi Anda menyimpan data yang diambil dari jaringan di penyimpanan lokal perangkat sehingga dapat menghasilkan akses yang lebih cepat.
Karena aplikasi akan bisa mendapatkan data dari jaringan serta menyimpan cache offline hasil yang telah didownload sebelumnya, Anda memerlukan cara agar aplikasi dapat mengatur beberapa sumber data ini. Anda akan melakukannya dengan mengimplementasikan class repositori yang akan berfungsi sebagai sumber kebenaran tunggal untuk data aplikasi dan memisahkan sumber data (jaringan, cache, dll.) dari model tampilan.
Yang harus sudah Anda ketahui
Anda harus memahami:
- Library persistensi data, Room.
- Menggunakan library jaringan Retrofit.
- Komponen Arsitektur Android,
ViewModel
,ViewModelFactory
, danLiveData
dasar. - Transformasi untuk class LiveData.
- Membuat dan meluncurkan coroutine.
- Adaptor binding di data binding.
Yang akan Anda pelajari
- Cara menerapkan repositori untuk memisahkan lapisan data aplikasi dari bagian aplikasi lainnya.
- Cara memuat data yang di-cache menggunakan repositori.
Yang akan Anda lakukan
- Menggunakan repositori untuk memisahkan lapisan data, lalu mengintegrasikan class repositori dengan
ViewModel
. - Menampilkan data dari cache offline.
2. Kode Awal
Mendownload kode project
Perhatikan bahwa nama folder adalah RepositoryPattern-Starter
. Pilih folder ini saat Anda membuka project di Android Studio.
Untuk mendapatkan kode codelab ini dan membukanya di Android Studio, lakukan hal berikut.
Mendapatkan kode
- Klik URL yang diberikan. Tindakan ini akan membuka halaman GitHub project di browser.
- Periksa dan konfirmasi nama cabang yang cocok dengan nama cabang yang ditentukan dalam codelab. Misalnya, dalam screenshot berikut, nama cabang adalah main (utama).
- Di halaman GitHub project, klik tombol Code yang akan menampilkan pop-up.
- Pada pop-up, klik tombol Download ZIP untuk menyimpan project di komputer. Tunggu download selesai.
- Temukan file di komputer Anda (mungkin di folder Downloads).
- Klik dua kali pada file ZIP untuk mengekstraknya. Tindakan ini akan membuat folder baru yang berisi file project.
Membuka project di Android Studio
- Mulai Android Studio.
- Di jendela Welcome to Android Studio, klik Open.
Catatan: Jika Android Studio sudah terbuka, pilih opsi menu File > Open.
- Di file browser, buka lokasi folder project yang telah diekstrak (kemungkinan ada di folder Downloads).
- Klik dua kali pada folder project tersebut.
- Tunggu Android Studio membuka project.
- Klik tombol Run untuk membangun dan menjalankan aplikasi. Pastikan aplikasi dibangun seperti yang diharapkan.
3. Ringkasan aplikasi awal
Aplikasi DevBytes menampilkan daftar video DevBytes dari Channel YouTube Android Developers dalam tampilan recycler yang dapat diklik pengguna untuk membuka link ke video.
Meskipun kode awal berfungsi sepenuhnya, kode ini memiliki kelemahan besar yang dapat berpengaruh negatif terhadap pengalaman pengguna. Jika pengguna memiliki koneksi yang buruk atau tidak ada koneksi internet sama sekali, video tidak akan ditampilkan. Hal ini terjadi meskipun aplikasi telah dibuka sebelumnya. Jika pengguna keluar dan meluncurkan kembali aplikasi, kali ini tanpa Internet, aplikasi akan mencoba untuk mendownload ulang daftar video, tetapi tetap gagal.
Anda dapat melihat cara kerjanya di emulator.
- Aktifkan mode pesawat untuk sementara di Android emulator (Settings App > Network & Internet > Airplane mode).
- Jalankan aplikasi DevBytes dan amati bahwa tidak ada apa-apa di layar.
- Pastikan Anda telah menonaktifkan Mode pesawat sebelum melanjutkan codelab.
Hal ini karena setelah aplikasi DevBytes mendownload data untuk pertama kalinya, tidak akan ada lagi data yang disimpan dalam cache untuk digunakan nanti. Aplikasi saat ini menyertakan database Room. Tugas Anda adalah menggunakannya untuk mengimplementasikan fungsi cache dan memperbarui model tampilan untuk menggunakan repositori, yang akan mendownload data baru, atau mengambilnya dari database Room. Class repositori memisahkan logika ini dari model tampilan sehingga kode Anda tetap teratur dan terpisah.
Project awal disusun menjadi beberapa paket.
Meskipun dipersilakan dan dianjurkan untuk memahami kode tersebut, Anda hanya akan membuka dua file: repositori/VideoRepository.kt dan viewmodels/DevByteViewModel. Pertama, Anda akan membuat class VideosRepository
yang menerapkan pola repositori untuk penyimpanan dalam cache (Anda akan mempelajari hal ini lebih lanjut dalam beberapa halaman berikutnya), lalu memperbarui DevByteViewModel
agar dapat menggunakan VideosRepository
Anda yang baru.
Namun, sebelum Anda langsung masuk ke kode, luangkan waktu untuk mempelajari lebih lanjut cache dan pola repositori.
4. Menyimpan ke cache dan pola repositori
Repositori
Pola repositori adalah pola desain yang mengisolasi lapisan data dari bagian aplikasi lainnya. Lapisan data mengacu pada bagian aplikasi Anda (terpisah dari UI) yang menangani data aplikasi dan logika bisnis, mengekspos API yang konsisten untuk seluruh aplikasi agar dapat mengakses data ini. Meskipun UI menyajikan informasi kepada pengguna, lapisan data mencakup hal-hal seperti kode jaringan, database Room, penanganan error, dan kode apa pun yang membaca atau memanipulasi data.
Repositori dapat menyelesaikan ketidaksesuaian antara sumber data (seperti model persisten, layanan web, dan cache) dan memusatkan perubahan pada data ini. Diagram di bawah menunjukkan cara komponen aplikasi seperti aktivitas berinteraksi dengan sumber data melalui repositori.
Untuk mengimplementasikan repositori, Anda harus menggunakan class terpisah seperti class VideosRepository
yang dibuat pada tugas berikutnya. Class repositori mengisolasi sumber data dari bagian aplikasi lainnya dan menyediakan API yang bersih untuk akses data ke seluruh aplikasi. Penggunaan class repositori memastikan kode ini terpisah dari class ViewModel
, dan ini merupakan praktik terbaik yang direkomendasikan untuk pemisahan dan arsitektur kode.
Keuntungan menggunakan repositori
Modul repositori menangani operasi data dan memungkinkan Anda menggunakan beberapa backend. Dalam aplikasi dunia nyata biasa, repositori menerapkan logika untuk memutuskan apakah perlu mengambil data dari jaringan atau menggunakan hasil yang telah di-cache di database lokal. Dengan repositori, Anda dapat menukar detail implementasi, seperti bermigrasi ke library persistensi yang berbeda, tanpa memengaruhi kode panggilan, seperti model tampilan. Hal ini juga membantu menjadikan kode Anda bersifat modular dan dapat diuji. Anda dapat dengan mudah meniru repositori dan menguji kode lainnya.
Repositori harus berfungsi sebagai sumber kebenaran tunggal untuk bagian tertentu dari data aplikasi Anda. Saat bekerja dengan beberapa sumber data, seperti resource jaringan dan cache offline, repositori memastikan data aplikasi seakurat dan seterbaru mungkin sehingga dapat memberikan pengalaman terbaik, bahkan saat aplikasi sedang offline.
Menyimpan ke cache
Cache adalah penyimpanan data yang digunakan oleh aplikasi Anda. Misalnya, Anda mungkin ingin menyimpan data dari jaringan untuk sementara jika koneksi internet pengguna terputus. Meskipun jaringan tidak lagi tersedia, aplikasi masih dapat kembali menggunakan data cache. Cache juga berguna untuk menyimpan data sementara untuk aktivitas yang tidak lagi ada di layar, atau bahkan mempertahankan data di sela-sela proses peluncuran aplikasi.
Cache dapat memiliki banyak bentuk, beberapa di antaranya lebih sederhana atau lebih kompleks, bergantung pada tugas tertentu. Tabel berikut menunjukkan beberapa cara untuk mengimplementasikan caching jaringan di Android.
Teknik caching | Penggunaan |
Retrofit adalah library jaringan yang digunakan untuk menerapkan klien REST yang aman jenisnya untuk Android. Anda dapat mengonfigurasi Retrofit untuk menyimpan salinan setiap hasil jaringan secara lokal. | Solusi yang baik untuk permintaan dan respons sederhana, panggilan jaringan yang jarang, atau set data kecil. |
Anda dapat menggunakan | Solusi yang baik untuk kunci dan nilai sederhana dalam jumlah kecil, seperti setelan aplikasi. Anda tidak dapat menggunakan teknik ini untuk menyimpan data terstruktur dalam jumlah besar. |
Anda dapat mengakses direktori penyimpanan internal aplikasi dan menyimpan file data di dalamnya. Nama paket aplikasi Anda menetapkan direktori penyimpanan internal aplikasi yang berada di lokasi khusus dalam sistem file Android. Direktori ini bersifat pribadi untuk aplikasi Anda, dan akan dihapus saat aplikasi Anda di-uninstal. | Solusi yang baik jika Anda memiliki kebutuhan khusus yang dapat diselesaikan oleh sistem file—misalnya, jika Anda perlu menyimpan file media atau file data, dan Anda harus mengelola file tersebut sendiri. Anda tidak dapat menggunakan teknik ini untuk menyimpan data kompleks dan terstruktur yang harus dibuat kueri oleh aplikasi Anda. |
Anda dapat menyimpan data dalam cache menggunakan Room yang merupakan library pemetaan objek SQLite yang menyediakan lapisan abstraksi atas SQLite. | Solusi yang disarankan untuk data yang dapat dikueri dan terstruktur kompleks; karena cara terbaik untuk menyimpan data terstruktur pada sistem file perangkat adalah dalam database SQLite lokal. |
Di codelab ini, Anda menggunakan Room karena cara ini direkomendasikan untuk menyimpan data terstruktur di sistem file perangkat. Aplikasi DevBytes sudah dikonfigurasi agar dapat menggunakan Room. Tugas Anda adalah mengimplementasikan caching offline menggunakan pola repositori untuk memisahkan lapisan data dari kode UI.
5. Mengimplementasikan VideoRepository
Tugas: Membuat repositori
Dalam tugas ini, Anda akan membuat repositori untuk mengelola cache offline yang telah diimplementasikan di tugas sebelumnya. Database Room tidak memiliki logika untuk mengelola cache offline. Database ini hanya memiliki metode untuk menyisipkan, memperbarui, menghapus, dan mengambil data. Repositori akan memiliki logika untuk mengambil hasil jaringan dan menjaga database tetap terbaru.
Langkah 1: Tambahkan repositori
- Di repository/VideoRepository.kt, buat kelas
VideosRepository
. Teruskan objekVideosDatabase
sebagai parameter konstruktor class untuk mengakses metode DAO.
class VideosRepository(private val database: VideosDatabase) {
}
- Di dalam class
VideosRepository
, tambahkan metodesuspend
yang disebutrefreshVideos()
yang tidak memiliki argumen dan tidak menampilkan apa pun. Metode ini akan menjadi API yang akan digunakan untuk memuat ulang cache offline.
suspend fun refreshVideos() {
}
- Di dalam metode
refreshVideos()
, alihkan konteks coroutine keDispatchers.IO
untuk menjalankan operasi jaringan dan database.
suspend fun refreshVideos() {
withContext(Dispatchers.IO) {
}
}
- Di dalam blok
withContext
, ambil playlist videoDevByte
dari jaringan menggunakan instance layanan Retrofit,DevByteNetwork
.
val playlist = DevByteNetwork.devbytes.getPlaylist()
- Di dalam metode
refreshVideos()
, setelah mengambil playlist dari jaringan, simpan playlist tersebut di database Room. Untuk menyimpan playlist, gunakan classVideosDatabase
. Aktifkan metode DAOinsertAll()
dengan meneruskan playlist yang diambil dari jaringan. Gunakan fungsi ekstensiasDatabaseModel()
untuk memetakan playlist ke objek database.
database.videoDao.insertAll(playlist.asDatabaseModel())
- Berikut adalah metode
refreshVideos()
lengkap dengan laporan log untuk melacak metode ketika diaktifkan:
suspend fun refreshVideos() {
withContext(Dispatchers.IO) {
val playlist = DevByteNetwork.devbytes.getPlaylist()
database.videoDao.insertAll(playlist.asDatabaseModel())
}
}
Langkah 2: Ambil data dari database
Pada langkah ini, Anda akan membuat objek LiveData
untuk membaca playlist video dari database. Objek LiveData
ini diperbarui secara otomatis saat database diperbarui juga. Fragmen yang dilampirkan, atau aktivitas, diperbarui dengan nilai baru.
- Di class
VideosRepository
, deklarasikan objekLiveData
yang disebutvideos
untuk menyimpan daftar objekDevByteVideo
. Inisialisasi objekvideos
menggunakandatabase.videoDao
. Aktifkan metode DAOgetVideos()
. Android Studio akan menampilkan error "ketidakcocokan jenis" karena metodegetVideos()
menampilkan daftar objek database, bukan daftar objekDevByteVideo
.
val videos: LiveData<List<DevByteVideo>> = database.videoDao.getVideos()
- Untuk memperbaiki error ini, gunakan
Transformations.map
untuk mengonversi daftar objek database menjadi daftar objek domain menggunakan fungsi konversiasDomainModel()
.
val videos: LiveData<List<DevByteVideo>> = Transformations.map(database.videoDao.getVideos()) {
it.asDomainModel()
}
Sekarang Anda telah mengimplementasikan repositori untuk aplikasi. Pada tugas berikutnya, Anda akan menggunakan strategi refresh sederhana untuk tetap memperbarui database lokal.
6. Menggunakan VideoRepository di DevByteViewModel
Tugas: Mengintegrasikan repositori menggunakan strategi refresh
Dalam tugas ini, Anda akan mengintegrasikan repositori dengan ViewModel
menggunakan strategi refresh sederhana. Anda menampilkan playlist video dari database Room, bukan mengambil langsung dari jaringan.
Muat ulang database adalah proses memperbarui atau memuat ulang database lokal agar tetap sinkron dengan data dari jaringan. Untuk aplikasi contoh ini, Anda akan menggunakan strategi refresh sederhana, yaitu modul yang meminta data dari repositori bertanggung jawab untuk memuat ulang data lokal.
Dalam aplikasi sebenarnya, strategi Anda mungkin akan lebih kompleks. Misalnya, kode Anda mungkin otomatis memperbarui data di latar belakang (dengan mempertimbangkan bandwidth), atau meng-cache data yang kemungkinan besar akan digunakan oleh pengguna berikutnya.
- Di viewmodels/DevByteViewModel.kt, di dalam class
DevByteViewModel
, buat variabel anggota pribadi yang disebutvideosRepository
dari jenisVideosRepository
. Buat instance variabel dengan meneruskan objekVideosDatabase
singleton.
private val videosRepository = VideosRepository(getDatabase(application))
- Di class
DevByteViewModel
, ganti metoderefreshDataFromNetwork()
dengan metoderefreshDataFromRepository()
. Metode lama,refreshDataFromNetwork()
, mengambil playlist video dari jaringan menggunakan library Retrofit. Metode baru memuat playlist video dari repositori. Repositori menentukan sumber (misalnya, jaringan, database, dll.) yang diambil oleh playlist sehingga mempertahankan detail implementasi dari model tampilan. Repositori juga menjadikan kode Anda lebih mudah dikelola sehingga Anda tidak perlu mengubah model tampilan jika ingin mengubah implementasi untuk mendapatkan data di masa mendatang.
private fun refreshDataFromRepository() {
viewModelScope.launch {
try {
videosRepository.refreshVideos()
_eventNetworkError.value = false
_isNetworkErrorShown.value = false
} catch (networkError: IOException) {
// Show a Toast error message and hide the progress bar.
if(playlist.value.isNullOrEmpty())
_eventNetworkError.value = true
}
}
}
- Di class
DevByteViewModel
, di dalam blokinit
, ubah panggilan fungsi darirefreshDataFromNetwork()
menjadirefreshDataFromRepository()
. Kode ini mengambil playlist video dari repositori, bukan langsung dari jaringan.
init {
refreshDataFromRepository()
}
- Di class
DevByteViewModel
, hapus properti_playlist
dan juga properti pendukungnya,playlist
.
Kode yang akan dihapus
private val _playlist = MutableLiveData<List<Video>>()
...
val playlist: LiveData<List<Video>>
get() = _playlist
- Di class
DevByteViewModel
, setelah membuat instance objekvideosRepository
, tambahkanval
baru bernamaplaylist
untuk menyimpan daftarLiveData
video dari repositori.
val playlist = videosRepository.videos
- Jalankan aplikasi Anda. Aplikasi berjalan seperti sebelumnya, tetapi sekarang playlist
DevBytes
diambil dari jaringan dan disimpan di database Room. Playlist ditampilkan di layar dari database Room, bukan langsung dari jaringan.
- Untuk melihat perbedaannya, aktifkan mode pesawat di emulator atau perangkat.
- Jalankan aplikasi sekali lagi. Perhatikan bahwa pesan toast "Error Jaringan" tidak ditampilkan. Playlist akan diambil dari cache offline lalu ditampilkan.
- Nonaktifkan mode pesawat di emulator atau perangkat.
- Tutup dan buka kembali aplikasi. Aplikasi akan memuat playlist dari cache offline, sembari permintaan jaringan berjalan di latar belakang.
Jika data baru masuk dari jaringan, layar akan otomatis diperbarui untuk menampilkan data baru. Namun, server DevBytes
tidak akan memuat ulang kontennya sehingga Anda tidak melihat data yang diperbarui.
Bagus sekali! Dalam codelab ini, Anda telah mengintegrasikan cache offline dengan ViewModel
untuk menampilkan playlist dari repositori, bukan mengambil playlist dari jaringan.
7. Kode Solusi
Kode solusi
Project Android Studio: RepositoryPattern
8. Selamat
Selamat! Dalam jalur ini, Anda telah mempelajari bahwa:
- Pembuatan cache adalah proses penyimpanan data yang diambil dari jaringan di penyimpanan perangkat. Caching memungkinkan aplikasi Anda mengakses data saat perangkat sedang offline, atau jika aplikasi Anda harus mengakses data yang sama lagi.
- Cara terbaik agar aplikasi Anda menyimpan data terstruktur pada sistem file perangkat adalah menggunakan database SQLite lokal. Room adalah library pemetaan objek SQLite, yang artinya Room menyediakan lapisan abstraksi atas SQLite. Menggunakan Room adalah praktik terbaik yang direkomendasikan untuk menerapkan caching offline.
- Class repositori mengisolasi sumber data, seperti database Room dan layanan web, dari seluruh aplikasi. Class repositori menyediakan API yang bersih untuk akses data ke aplikasi lainnya.
- Menggunakan repositori adalah praktik terbaik yang direkomendasikan untuk arsitektur dan pemisahan kode.
- Saat Anda mendesain cache offline, praktik terbaik adalah memisahkan objek jaringan, domain, dan database aplikasi. Strategi ini adalah contoh pemisahan fokus.