Pertemuan 12 - Halaman Login
Aplikasi Login Sederhana dengan Room Database + MVVM Architecture
Nama: Christoforus Indra Bagus Pratama
NRP: 5025231124
Mata Kuliah: Pemrograman Perangkat Bergerak
Tanggal: 6 Mei 2026
Pertemuan: 12
Link: Link Github
1. Deskripsi Aplikasi dan Tujuan Pembuatan
1.1 Deskripsi Umum
Pada project Pertemuan 12 ini, saya membuat aplikasi Android yang sederhana namun fungsional untuk proses autentikasi (login) pengguna. Aplikasi ini dibangun menggunakan Jetpack Compose untuk antarmuka pengguna dan Room Database sebagai sistem penyimpanan data lokal di perangkat. Fitur-fitur utama yang saya implementasikan mencakup form input username dan password, tombol login, validasi kredensial terhadap data di database lokal, serta menampilkan pesan feedback yang jelas (pesan sukses atau pesan kesalahan).
1.2 Tujuan Pembuatan
Tujuan utama pembuatan aplikasi ini adalah untuk mendalami beberapa konsep penting dalam mobile programming modern:
Memahami alur autentikasi dasar: Bagaimana cara menangkap input user, memvalidasinya terhadap data yang disimpan, dan memberikan response yang sesuai.
Menguasai Room Database: Bagaimana cara menggunakan Room untuk membuat tabel, menjalankan query, dan memanipulasi data secara aman melalui DAO.
Menerapkan pola MVVM: Memisahkan tanggung jawab kode antara UI (View), logika bisnis (ViewModel), dan akses data (Repository + DAO + Entity), agar code lebih mudah dirawat, diuji, dan dikembangkan.
Menggunakan Coroutine: Menjalankan operasi database di background thread sehingga UI tetap responsif dan tidak freeze.
Menerapkan Jetpack Compose: Membangun interface deklaratif yang modern, efisien, dan mudah dikelola dibandingkan XML tradisional.
2. Arsitektur Aplikasi (MVVM Architecture)
2.1 Penjelasan Pola MVVM
MVVM (Model-View-ViewModel) adalah pola arsitektur yang membagi aplikasi menjadi tiga lapisan utama dengan tanggung jawab yang jelas dan terpisah. Pola ini memudahkan pengembangan, testing, dan pemeliharaan kode dalam jangka panjang.
2.2 Tiga Lapisan dalam Aplikasi Ini
| Lapisan | File/Class | Tanggung Jawab | Penjelasan |
|---|---|---|---|
| View | LoginScreen.kt |
Menampilkan UI dan menerima input user | Berisi Composable function untuk form login, tidak punya logika bisnis, hanya menerima state dari ViewModel dan mengirim event saat user berinteraksi. |
| ViewModel | LoginViewModel.kt, LoginViewModelFactory.kt |
Mengelola state UI dan logika bisnis login | Menyimpan state login (string pesan sukses/gagal), menerima event login dari View, mengakses Repository untuk validasi, dan update state yang otomatis di-reflect ke UI. |
| Model/Data | User.kt (Entity), UserDao.kt (DAO), AppDatabase.kt (Database), UserRepository.kt (Repository) |
Mengelola penyimpanan dan akses data | Entity mendefinisikan tabel, DAO menyediakan query, AppDatabase menghubungkan Entity dengan DAO, Repository menjadi interface antara ViewModel dan Database sehingga ViewModel tidak perlu tahu detail database. |
2.3 Alur Data Aplikasi
Alur data pada aplikasi ini mengikuti pola unidirectional (satu arah) yang konsisten: View → ViewModel → Repository → DAO → Room/SQLite, kemudian kembali ke ViewModel sebagai state, lalu Compose otomatis me-refresh tampilan View. Alur ini memastikan data mengalir dengan teratur dan dapat diprediksi, sehingga debugging dan testing menjadi lebih mudah.
| Tahap | Komponen | Aksi |
|---|---|---|
| 1 | User / View | User mengetik username dan password, lalu menekan tombol LOGIN. |
| 2 | LoginScreen (Composable) | Menangkap input dan memanggil viewModel.login(username, password). |
| 3 | LoginViewModel | Menerima username/password, memanggil repository.login(username, password) dalam Coroutine viewModelScope.launch. |
| 4 | UserRepository | Meneruskan permintaan login ke userDao.login(username, password). |
| 5 | UserDao | Menjalankan SQL Query: SELECT * FROM users WHERE username = :username AND password = :password. |
| 6 | Room/SQLite | Database mencari record yang cocok, mengembalikan User object atau null. |
| 7 | LoginViewModel (ViewModel menerima hasil) | Update state loginState ke "Login Berhasil ✓" atau "Username atau Password Salah ✗". |
| 8 | LoginScreen (View menerima state baru) | Compose mendeteksi perubahan state, melakukan recomposition, menampilkan pesan result ke user. |
3. Langkah-Langkah Pembuatan Aplikasi (Detail Implementasi)
3.1 Langkah 1: Persiapan Project
Pertama-tama, saya membuat project Android baru di Android Studio dengan nama Pertemuan 12 dan menggunakan package name com.example.pertemuan12. Project ini menggunakan Jetpack Compose sebagai default untuk UI. Setelah project terbuat, saya memastikan build tools dan SDK terbaru sudah tersedia, kemudian melakukan sync dan verifikasi bahwa project dapat di-build tanpa error.
3.2 Langkah 2: Menambahkan Dependency
Saya membuka file app/build.gradle.kts dan menambahkan dependency yang diperlukan. Dependency utama yang ditambahkan adalah:
androidx.room:room-runtime— library utama Room untuk database lokal.androidx.room:room-ktx— extension Kotlin untuk Room yang mempermudah penggunaan suspend function dan Coroutine.androidx.room:room-compilervia KSP — compiler yang menghasilkan kode SQL dari anotasi @Query dan @Insert.androidx.lifecycle:lifecycle-viewmodel-compose— integrasi ViewModel dengan Compose.kotlinx.coroutines— library untuk asynchronous programming di Kotlin.
3.3 Langkah 3: Membuat Entity (User.kt)
Entity adalah representasi tabel database dalam bentuk Kotlin data class. Saya membuat file data/local/entity/User.kt yang mendefinisikan struktur tabel users dengan tiga kolom: id (primary key auto-increment), username (string), dan password (string).
3.4 Langkah 4: Membuat DAO (UserDao.kt)
DAO (Data Access Object) adalah interface yang mendefinisikan operasi database yang dapat dilakukan. Saya membuat file data/local/dao/UserDao.kt berisi dua function utama: insert(user: User) untuk menambah user baru, dan login(username, password): User? untuk validasi login.
3.5 Langkah 5: Membuat Database Class (AppDatabase.kt)
File data/local/database/AppDatabase.kt adalah abstract class yang berperan sebagai access point ke database. Saya menambahkan anotasi @Database(entities = [User::class], version = 1), abstract function userDao(): UserDao, dan companion object dengan pola Singleton untuk memastikan hanya ada satu instance database selama aplikasi berjalan.
3.6 Langkah 6: Membuat Repository (UserRepository.kt)
Repository berfungsi sebagai perantara antara ViewModel dan DAO, sehingga ViewModel tidak perlu mengetahui detail implementasi database. File data/repository/UserRepository.kt menerima UserDao sebagai parameter konstruktor dan menyediakan function insert() dan login() yang meneruskan operasi ke DAO.
3.7 Langkah 7: Membuat ViewModel (LoginViewModel.kt)
ViewModel menyimpan state UI dan logika bisnis. Saya membuat viewmodel/LoginViewModel.kt yang extends ViewModel, berisi state loginState menggunakan mutableStateOf("") agar Compose dapat memantau perubahannya. Function login() memanggil repository dalam coroutine scope, dan function insertDummyUser() menambahkan akun default admin/12345 saat aplikasi pertama kali launch.
3.8 Langkah 8: Membuat ViewModelFactory (LoginViewModelFactory.kt)
Karena LoginViewModel memerlukan parameter UserRepository, saya perlu membuat factory untuk instantiate ViewModel dengan benar. File viewmodel/LoginViewModelFactory.kt mengimplementasikan ViewModelProvider.Factory dan override function create() untuk membuat LoginViewModel dengan repository yang sudah di-inject.
3.9 Langkah 9: Membuat LoginScreen (ui/screen/LoginScreen.kt)
Ini adalah layer View yang berisi UI Compose. File ui/screen/LoginScreen.kt adalah Composable function yang menampilkan form login dengan: title, subtitle, OutlinedTextField untuk username dan password, button LOGIN, dan card untuk menampilkan pesan hasil login (sukses atau gagal).
3.10 Langkah 10: Setup MainActivity
Terakhir, saya mengkonfigurasi MainActivity.kt sebagai entry point aplikasi. Di sini, saya menginisialisasi rantai dependency dari AppDatabase hingga ViewModel, memanggil insertDummyUser() dalam LaunchedEffect, dan menampilkan LoginScreen(viewModel) di dalam Surface dengan tema Pertemuan12Theme.
4. Penjelasan File, Isi Kode, dan Tujuan Masing-Masing
4.1 Tabel Ringkasan File-File Utama
| Kategori | File | Tujuan | Isi Kode Utama |
|---|---|---|---|
| Entry Point | MainActivity.kt |
Activity utama aplikasi, mengatur alur lifecycle dan menginisialisasi dependencies | onCreate() untuk setup Compose, rantai initialization database → repository → viewmodel, LaunchedEffect untuk insert dummy user |
AndroidManifest.xml |
Konfigurasi manifest aplikasi | Deklarasi MainActivity sebagai launcher activity, permission (jika ada) | |
| UI/View Layer | ui/screen/LoginScreen.kt |
Composable UI untuk form login | Column layout, OutlinedTextField untuk username/password, Button LOGIN, Card untuk menampilkan status |
| ViewModel Layer | viewmodel/LoginViewModel.kt |
Logic bisnis dan state management login | mutableStateOf untuk loginState, function login(), function insertDummyUser(), viewModelScope.launch untuk coroutine |
viewmodel/LoginViewModelFactory.kt |
Factory untuk membuat LoginViewModel dengan dependency injection | class yang extends ViewModelProvider.Factory, override create() untuk instantiate LoginViewModel(repository) | |
| Repository Layer | data/repository/UserRepository.kt |
Perantara antara ViewModel dan Data Layer (DAO) | Class yang menerima UserDao, menyediakan suspend function insert() dan login() |
| Entity (Model) | data/local/entity/User.kt |
Representasi tabel users di database | @Entity data class dengan @PrimaryKey id, username, password |
| DAO | data/local/dao/UserDao.kt |
Interface untuk operasi database (insert, query) | @Dao interface, @Insert suspend fun insert(user: User), @Query suspend fun login(username, password) |
| Database | data/local/database/AppDatabase.kt |
Konfigurasi database dan singleton instance | @Database abstract class, abstract fun userDao(), companion object dengan fun getDatabase(context) Singleton pattern |
| Theme & Resources | ui/theme/Color.kt |
Definisi warna-warna aplikasi | Color objects (Purple80, Purple40, dll) |
ui/theme/Theme.kt |
Konfigurasi Material Theme 3 | @Composable Pertemuan12Theme dengan color scheme, typography | |
ui/theme/Type.kt |
Definisi typography (ukuran font, style teks) | Typography object dengan default text styles | |
| Config & Build | app/build.gradle.kts |
Konfigurasi build dan dependencies aplikasi | Room dependencies, KSP plugin, Coroutines, Lifecycle ViewModel, Compose libraries |
build.gradle.kts (root) |
Konfigurasi build tingkat project | Plugin declarations untuk Android, Kotlin, Compose |
5. Penjelasan Detail Setiap Bagian Kode MainActivity.kt
5.1 Struktur Umum MainActivity
MainActivity adalah Activity utama yang berjalan saat aplikasi di-launch. File ini mengandung logic setup aplikasi, inisialisasi dependencies, dan render UI Compose. Berikut adalah penjelasan per bagian dari kode MainActivity.kt.
5.2 Bagian 1: Package dan Import
package com.example.pertemuan12
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Surface
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier
import androidx.lifecycle.viewmodel.compose.viewModel
// ... lebih banyak import
Bagian ini berisi deklarasi package aplikasi dan impor semua library yang diperlukan. Library-library ini termasuk:
- androidx.activity: ComponentActivity adalah base class Activity modern yang support Compose.
- androidx.compose.*: Semua komponen Compose untuk build UI deklaratif.
- androidx.lifecycle.viewmodel.compose: Function viewModel() untuk access ViewModel dari Compose.
- Custom imports: Database, Repository, ViewModel, dan UI screen yang telah kita buat.
5.3 Bagian 2: Class Declaration dan onCreate()
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
MainActivity mewarisi ComponentActivity, bukan Activity biasa, karena ComponentActivity dirancang khusus untuk support Compose. Function override onCreate() dipanggil saat Activity dibuat. Perintah enableEdgeToEdge() mengaktifkan layout agar dapat menggunakan seluruh layar termasuk area status bar dan navigation bar. Function setContent { } adalah tempat mendefinisikan seluruh UI berbasis Compose.
5.4 Bagian 3: Theme dan Surface Wrapper
setContent {
Pertemuan12Theme {
Surface(modifier = Modifier.fillMaxSize()) {
Pertemuan12Theme adalah Composable function yang menerapkan Material Theme 3 ke seluruh aplikasi, memastikan warna, typography, dan style komponen konsisten. Surface adalah komponen yang berfungsi sebagai container utama dengan background, dan fillMaxSize() membuat Surface memenuhi seluruh layar.
5.5 Bagian 4: Inisialisasi Dependency Chain
val database = AppDatabase.getDatabase(this@MainActivity)
val userDao = database.userDao()
val repository = UserRepository(userDao)
val factory = LoginViewModelFactory(repository)
val viewModel: LoginViewModel = viewModel(factory = factory)
Ini adalah core dari Dependency Injection manual. Rantainya adalah:
AppDatabase.getDatabase(context)— Membuat atau mengambil singleton instance database Room.database.userDao()— Mendapatkan DAO interface dari database untuk akses tabel users.UserRepository(userDao)— Membuat instance Repository yang diberi userDao sebagai dependency.LoginViewModelFactory(repository)— Membuat factory yang tahu cara membuat LoginViewModel dengan repository.viewModel(factory = factory)— Function dari Compose yang membuat LoginViewModel menggunakan factory yang sudah disiapkan.
5.6 Bagian 5: LaunchedEffect untuk Insert Data Dummy
LaunchedEffect(Unit) {
viewModel.insertDummyUser()
}
LaunchedEffect adalah Composable effect yang dijalankan saat composable masuk ke composition. Parameter Unit berarti effect hanya dijalankan sekali (tidak ada dependency). Di sini, kita memanggil insertDummyUser() untuk menyisipkan akun default admin/12345 ke database pada saat pertama kali aplikasi launch. Ini memastikan selalu ada data untuk login testing.
5.7 Bagian 6: Render LoginScreen
LoginScreen(viewModel)
}
}
}
}
}
Terakhir, kita memanggil LoginScreen(viewModel) untuk menampilkan UI login screen. ViewModel diberikan sebagai parameter sehingga LoginScreen dapat mengakses state dan memanggil function login() dari ViewModel.
6. Tree Struktur Folder Aplikasi dan Alur Lalu Lintas Data
6.1 Struktur Folder Aplikasi
Pertemuan 12/
├── app/
│ ├── build.gradle.kts
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ ├── java/com/example/pertemuan12/
│ │ ├── MainActivity.kt
│ │ ├── data/
│ │ │ ├── local/
│ │ │ │ ├── entity/
│ │ │ │ │ └── User.kt
│ │ │ │ ├── dao/
│ │ │ │ │ └── UserDao.kt
│ │ │ │ └── database/
│ │ │ │ └── AppDatabase.kt
│ │ │ └── repository/
│ │ │ └── UserRepository.kt
│ │ ├── viewmodel/
│ │ │ ├── LoginViewModel.kt
│ │ │ └── LoginViewModelFactory.kt
│ │ └── ui/
│ │ ├── screen/
│ │ │ └── LoginScreen.kt
│ │ └── theme/
│ │ ├── Color.kt
│ │ ├── Theme.kt
│ │ └── Type.kt
│ └── res/
│ ├── values/
│ │ ├── strings.xml
│ │ ├── colors.xml
│ │ └── themes.xml
│ ├── mipmap-*/
│ │ └── ic_launcher.webp
│ └── xml/
│ ├── backup_rules.xml
│ └── data_extraction_rules.xml
├── build.gradle.kts (root)
├── settings.gradle.kts
└── gradle/
6.2 Penjelasan Struktur Folder
| Folder/File | Kegunaan | Penjelasan |
|---|---|---|
data/ |
Data Layer — semua kode terkait akses dan model data | Berisi subfolder local (untuk database lokal), repository (perantara akses data). |
data/local/entity/ |
Entity class (model tabel database) | User.kt mendefinisikan struktur tabel users dengan anotasi @Entity dan @PrimaryKey. |
data/local/dao/ |
Data Access Object — interface query database | UserDao.kt berisi anotasi @Insert dan @Query untuk operasi database yang akan di-generate Room menjadi SQL otomatis. |
data/local/database/ |
Konfigurasi database Room | AppDatabase.kt adalah abstract class yang di-anotasi @Database, menjadi entry point untuk akses database. |
data/repository/ |
Repository pattern — abstraction layer | UserRepository.kt menyembunyikan detail DAO dari ViewModel, menyediakan interface clean untuk akses data. |
viewmodel/ |
ViewModel Layer — state management dan business logic | LoginViewModel.kt menyimpan UI state, logic login; LoginViewModelFactory.kt untuk dependency injection ViewModel. |
ui/screen/ |
Composable screen (halaman UI) | LoginScreen.kt adalah Composable function yang menampilkan form login dan feedback message. |
ui/theme/ |
Styling dan tema aplikasi | Color.kt (definisi warna), Theme.kt (aplikasi Material Theme 3), Type.kt (typography). |
res/values/ |
Resource strings, colors, themes XML | strings.xml (teks app_name), colors.xml (warna), themes.xml (tema Android Material). |
res/mipmap-*/ |
Icon launcher aplikasi dalam berbagai resolusi | ic_launcher.webp, ic_launcher_round.webp untuk berbagai density (mdpi, hdpi, xhdpi, dll). |
6.3 Alur Lalu Lintas Data (Data Flow)
Data mengalir dengan pola unidirectional yang teratur di aplikasi ini:
User Input (View): User mengetik username dan password pada OutlinedTextField di LoginScreen, lalu menekan tombol LOGIN.
Event ke ViewModel: LoginScreen memanggil callback
viewModel.login(username, password).ViewModel Processing: LoginViewModel.login() memanggil
repository.login(username, password)di dalam Coroutine scope viewModelScope.launch agar tidak block UI thread.Repository Forward: UserRepository.login() meneruskan permintaan ke
userDao.login(username, password).Database Query: UserDao menjalankan SQL query
SELECT * FROM users WHERE username = :username AND password = :password. Room compiler sudah mengubah @Query anotasi menjadi SQL implementation.Database Result: SQLite mengembalikan User object jika cocok, atau null jika tidak ada.
Back to ViewModel: Hasil kembali ke ViewModel. Jika user != null, set loginState = "Login Berhasil ✓", else set "Username atau Password Salah ✗".
State Update & Recomposition: loginState adalah mutableStateOf, jadi Compose otomatis mendeteksi perubahan state dan melakukan recomposition. LoginScreen di-render ulang dengan pesan baru.
UI Feedback (View): User melihat pesan hasil login (sukses atau gagal) dalam Card di bawah tombol LOGIN.
7. Cara Pengujian di Android Studio
7.1 Persiapan Sebelum Testing
Sebelum melakukan testing, pastikan beberapa hal telah dipersiaplan dengan baik untuk memastikan aplikasi dapat berjalan tanpa hambatan.
Buka Project: Buka project Pertemuan 12 di Android Studio, tunggu proses indexing file selesai (biasanya 1-2 menit tergantung kecepatan komputer).
Gradle Sync: Jalankan File > Sync Now atau tunggu Android Studio otomatis menyarankan sync. Pastikan semua dependency berhasil di-download dan tidak ada error merah.
Check Build: Buka Build Console dan pastikan tidak ada error atau warning yang kritis. Jika ada warning atau error, baca pesan dan fix sesuai saran.
7.2 Langkah-Langkah Testing
Clean & Build Project: Klik menu Build > Clean Project untuk membersihkan build artifacts lama, lalu Build > Rebuild Project untuk rebuild semuanya dari nol.
Jalankan Emulator: Jika menggunakan emulator (bukan device fisik), buka Android Virtual Device (AVD) Manager, pilih emulator yang kompatibel (minimal API 24 / Android 7.0), dan jalankan emulator tersebut. Tunggu emulator sepenuhnya boot (layar hidup, home screen terlihat).
Run App: Klik tombol Run (Play icon) di toolbar, atau tekan Shift+F10. Pilih emulator yang sedang berjalan, lalu klik OK. Android Studio akan melakukan compile, generate APK, dan install aplikasi ke emulator.
Tunggu App Launch: Tunggu aplikasi selesai di-install dan ter-launch secara otomatis. Jika berhasil, akan muncul UI login screen di emulator.
Monitor Logcat: Buka window Logcat (biasanya di tab bawah Android Studio) dan filter log dengan tag aplikasi untuk memastikan tidak ada crash atau exception saat aplikasi startup.
7.3 Scenario Testing
Setelah aplikasi berhasil launch, lakukan pengujian dengan tiga skenario berikut untuk memastikan fitur login berfungsi dengan baik.
| No | Skenario | Input | Aksi | Expected Result |
|---|---|---|---|---|
| 1 | Tampilan Awal (Sebelum Login) | - | Amati UI saat aplikasi pertama kali dibuka | Form username dan password kosong, tombol LOGIN aktif, tidak ada pesan error, text "admin / 12345" terlihat di bawah sebagai hint |
| 2 | Login Gagal | Username: admin, Password: 11111 | Ketik username dan password salah, tekan tombol LOGIN | Card merah dengan pesan "Username atau Password Salah ✗" muncul di bawah tombol. Input field tetap terisi. |
| 3 | Login Berhasil | Username: admin, Password: 12345 | Ketik username dan password benar, tekan tombol LOGIN | Card hijau dengan pesan "Login Berhasil ✓" muncul di bawah tombol. Tidak ada crash atau error di Logcat. |
8. Hasil Pengujian dan Area Placeholder untuk Screenshot
Berikut adalah tabel yang merangkum hasil testing aplikasi dengan tiga kondisi utama.
| Kondisi Uji | Hasil Observasi | Screenshot Hasil |
|---|---|---|
| Kondisi 1: Sebelum Mencoba Login |
|
|
| Kondisi 2: Login Gagal (Kredensial Salah) |
|
|
| Kondisi 3: Login Berhasil (Kredensial Benar) |
|
9. Kesimpulan
Dari pengembangan dan testing project aplikasi login ini, saya telah mempelajari beberapa hal penting dalam mobile programming modern. Pertama, pembuatan fitur autentikasi yang stabil dan aman memerlukan arsitektur yang terstruktur dengan baik — tidak hanya bisa berfungsi, tetapi juga mudah dimaintain dan di-test di masa depan.
Dengan menerapkan pola MVVM dan pemisahan layer yang jelas (View, ViewModel, Repository, DAO, Entity), kode menjadi lebih terorganisir dan scalable. ViewModel menangani state dan logic, sehingga UI hanya fokus menampilkan dan menerima input. Repository menjadi abstraction layer yang menyembunyikan kompleksitas database dari ViewModel, memudahkan testing dengan mock data.
Room Database memberikan solusi yang jauh lebih aman dan mudah dibanding SQLite manual — type-safe, automatic SQL generation, dan support untuk Coroutine membuat operasi database menjadi seamless. Penggunaan Jetpack Compose untuk UI membuat code lebih deklaratif dan mudah dibaca dibanding XML tradisional, dengan hot reload untuk development cycle yang lebih cepat.
Secara keseluruhan, project Pertemuan 12 ini telah berhasil mengimplementasikan aplikasi login sederhana dengan semua fitur yang diminta: input username/password, tombol login, validasi ke database lokal, pesan sukses/gagal, dan penyimpanan data user dengan aman. Aplikasi ini siap sebagai fondasi untuk pengembangan lebih lanjut, misalnya penambahan fitur register, hash password, atau autentikasi dengan server backend.
Materi yang dipelajari dari project ini mencakup konsep fundamental yang akan terus digunakan di project-project Android selanjutnya. Dengan pemahaman yang solid tentang MVVM, Database, Coroutine, dan Compose, saya siap untuk mengembangkan aplikasi Android yang lebih kompleks dan profesional di masa depan.




Komentar
Posting Komentar