Pola Repositori

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:

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

  1. Klik URL yang diberikan. Tindakan ini akan membuka halaman GitHub project di browser.
  2. Periksa dan konfirmasi nama cabang yang cocok dengan nama cabang yang ditentukan dalam codelab. Misalnya, dalam screenshot berikut, nama cabang adalah main (utama).

8cf29fa81a862adb.png

  1. Di halaman GitHub project, klik tombol Code yang akan menampilkan pop-up.

1debcf330fd04c7b.png

  1. Pada pop-up, klik tombol Download ZIP untuk menyimpan project di komputer. Tunggu download selesai.
  2. Temukan file di komputer Anda (mungkin di folder Downloads).
  3. Klik dua kali pada file ZIP untuk mengekstraknya. Tindakan ini akan membuat folder baru yang berisi file project.

Membuka project di Android Studio

  1. Mulai Android Studio.
  2. Di jendela Welcome to Android Studio, klik Open.

d8e9dbdeafe9038a.png

Catatan: Jika Android Studio sudah terbuka, pilih opsi menu File > Open.

8d1fda7396afe8e5.png

  1. Di file browser, buka lokasi folder project yang telah diekstrak (kemungkinan ada di folder Downloads).
  2. Klik dua kali pada folder project tersebut.
  3. Tunggu Android Studio membuka project.
  4. Klik tombol Run 8de56cba7583251f.png 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.

9757e53b89d2de7c.png

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.

  1. Aktifkan mode pesawat untuk sementara di Android emulator (Settings App > Network & Internet > Airplane mode).
  2. Jalankan aplikasi DevBytes dan amati bahwa tidak ada apa-apa di layar.

f0365b27d0dd8f78.png

  1. 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.

25b5f8d0997df54c.png

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.

9e528301efd49aea.png

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.

69021c8142d29198.png

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 DataStore untuk menyimpan pasangan nilai kunci.

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

  1. Di repository/VideoRepository.kt, buat kelas VideosRepository. Teruskan objek VideosDatabase sebagai parameter konstruktor class untuk mengakses metode DAO.
class VideosRepository(private val database: VideosDatabase) {
}
  1. Di dalam class VideosRepository, tambahkan metode suspend yang disebut refreshVideos() 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() {
}
  1. Di dalam metode refreshVideos(), alihkan konteks coroutine ke Dispatchers.IO untuk menjalankan operasi jaringan dan database.
suspend fun refreshVideos() {
   withContext(Dispatchers.IO) {
   }
}
  1. Di dalam blok withContext, ambil playlist video DevByte dari jaringan menggunakan instance layanan Retrofit, DevByteNetwork.
val playlist = DevByteNetwork.devbytes.getPlaylist()
  1. Di dalam metode refreshVideos(), setelah mengambil playlist dari jaringan, simpan playlist tersebut di database Room. Untuk menyimpan playlist, gunakan class VideosDatabase. Aktifkan metode DAO insertAll() dengan meneruskan playlist yang diambil dari jaringan. Gunakan fungsi ekstensi asDatabaseModel() untuk memetakan playlist ke objek database.
database.videoDao.insertAll(playlist.asDatabaseModel())
  1. 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.

  1. Di class VideosRepository, deklarasikan objek LiveData yang disebut videos untuk menyimpan daftar objek DevByteVideo. Inisialisasi objek videos menggunakan database.videoDao. Aktifkan metode DAO getVideos(). Android Studio akan menampilkan error "ketidakcocokan jenis" karena metode getVideos() menampilkan daftar objek database, bukan daftar objek DevByteVideo.
val videos: LiveData<List<DevByteVideo>> = database.videoDao.getVideos()
  1. Untuk memperbaiki error ini, gunakan Transformations.map untuk mengonversi daftar objek database menjadi daftar objek domain menggunakan fungsi konversi asDomainModel().
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.

  1. Di viewmodels/DevByteViewModel.kt, di dalam class DevByteViewModel, buat variabel anggota pribadi yang disebut videosRepository dari jenis VideosRepository. Buat instance variabel dengan meneruskan objek VideosDatabase singleton.
private val videosRepository = VideosRepository(getDatabase(application))
  1. Di class DevByteViewModel, ganti metode refreshDataFromNetwork() dengan metode refreshDataFromRepository(). 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
       }
   }
}
  1. Di class DevByteViewModel, di dalam blok init, ubah panggilan fungsi dari refreshDataFromNetwork() menjadi refreshDataFromRepository(). Kode ini mengambil playlist video dari repositori, bukan langsung dari jaringan.
init {
   refreshDataFromRepository()
}
  1. 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
  1. Di class DevByteViewModel, setelah membuat instance objek videosRepository, tambahkan val baru bernama playlist untuk menyimpan daftar LiveData video dari repositori.
val playlist = videosRepository.videos
  1. 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.

30ee74d946a2f6ca.png

  1. Untuk melihat perbedaannya, aktifkan mode pesawat di emulator atau perangkat.
  2. Jalankan aplikasi sekali lagi. Perhatikan bahwa pesan toast "Error Jaringan" tidak ditampilkan. Playlist akan diambil dari cache offline lalu ditampilkan.
  3. Nonaktifkan mode pesawat di emulator atau perangkat.
  4. 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.

Pelajari lebih lanjut