Pertemuan 12

Nama  : Triana Velia Hutabalian
NRP   : 5025231190
Kelas  : PPB (B)

Pada latihan ini, kami membuat aplikasi Login App menggunakan Kotlin dan View Binding di Android Studio. Aplikasi ini merupakan sistem autentikasi sederhana yang menyimpan data pengguna secara lokal menggunakan Room Database. Konsep utama yang diterapkan meliputi pembuatan Entity dan DAO untuk operasi database, pengelolaan navigasi antar halaman dengan Intent, validasi input form, serta operasi database asinkron menggunakan Coroutines dan lifecycleScope.

1
Membuat project baru di Android Studio dengan template Empty Views Activity, nama project LoginApp, package com.example.loginapp, bahasa Kotlin, dan Minimum SDK API 24.
2
Menambahkan versi dependency di gradle/libs.versions.toml yaitu room = "2.7.1", ksp = "2.0.21-1.0.28", dan coroutines = "1.9.0", lalu mendaftarkan library dan plugin terkait pada bagian [libraries] dan [plugins].
3
Mengaktifkan plugin ksp dan fitur viewBinding = true di app/build.gradle.kts, serta menambahkan dependency room-runtime, room-ktx, room-compiler (via ksp), dan kotlinx-coroutines-android. Menambahkan android.disallowKotlinSourceSets=false di gradle.properties agar KSP kompatibel dengan AGP 9.x.
4
Membuat data class User di package data/ dengan anotasi @Entity(tableName = "users"), properti id sebagai @PrimaryKey(autoGenerate = true), serta properti username dan password.
5
Membuat UserDao dengan anotasi @Dao berisi tiga fungsi suspend: insertUser() dengan @Insert, login() dengan query SELECT berdasarkan username dan password, serta getUserByUsername() untuk mengecek duplikasi username saat registrasi.
6
Membuat AppDatabase dengan anotasi @Database yang mengextend RoomDatabase, mengimplementasikan pola Singleton menggunakan companion object dan blok synchronized agar hanya satu instance database yang dibuat selama siklus hidup aplikasi.
7
Membuat layout activity_main.xml sebagai halaman login menggunakan ScrollView dan ConstraintLayout, berisi logo aplikasi, judul, TextInputLayout untuk username dan password (dengan toggle visibilitas), TextView untuk pesan hasil login, tombol Masuk, dan link teks Daftar.
8
Membuat activity_register.xml dengan tiga field input (username, password, konfirmasi password) dan activity_home.xml dengan CardView bergradien ungu yang menampilkan nama pengguna yang berhasil login beserta tombol Keluar.
9
Mengimplementasikan logika login di MainActivity.kt menggunakan View Binding dan lifecycleScope.launch untuk memanggil userDao().login() secara asinkron. Jika berhasil, aplikasi berpindah ke HomeActivity dengan membawa data username melalui Intent.putExtra(); jika gagal, menampilkan pesan error berwarna merah.
10
Mengimplementasikan RegisterActivity.kt dengan validasi lengkap: username minimal 4 karakter, password minimal 6 karakter, konfirmasi password harus cocok, dan pengecekan username duplikat ke database sebelum menyimpan. Membuat HomeActivity.kt dengan dialog konfirmasi logout menggunakan OnBackPressedCallback (API modern, non-deprecated).
Room Database

ORM resmi Android untuk penyimpanan data lokal — menyediakan abstraksi di atas SQLite dengan type-safety dan integrasi Kotlin Coroutines.

@Entity & @Dao

Entity mendefinisikan struktur tabel database, sedangkan DAO menyediakan antarmuka fungsi untuk operasi insert, query, update, dan delete.

View Binding

Fitur AGP yang menghasilkan class binding untuk setiap layout — menggantikan findViewById dengan akses view yang type-safe dan null-safe.

lifecycleScope

Coroutine scope yang terikat pada siklus hidup Activity — secara otomatis membatalkan coroutine ketika Activity dihancurkan, mencegah memory leak.

Singleton Pattern

Pola desain yang memastikan hanya satu instance AppDatabase yang ada, diimplementasikan dengan @Volatile dan synchronized.

Intent & Navigation

Mekanisme perpindahan antar Activity menggunakan Intent dengan putExtra() untuk mengirim data, dan flag FLAG_ACTIVITY_CLEAR_TASK untuk membersihkan back stack saat logout.

data/User.kt
package com.example.loginapp.data

import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "users")
data class User(
    @PrimaryKey(autoGenerate = true)
    val id: Int = 0,
    val username: String,
    val password: String
)
data/UserDao.kt
package com.example.loginapp.data

import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query

@Dao
interface UserDao {

    @Insert(onConflict = OnConflictStrategy.ABORT)
    suspend fun insertUser(user: User)

    @Query("SELECT * FROM users WHERE username = :username AND password = :password LIMIT 1")
    suspend fun login(username: String, password: String): User?

    @Query("SELECT * FROM users WHERE username = :username LIMIT 1")
    suspend fun getUserByUsername(username: String): User?
}
data/AppDatabase.kt
package com.example.loginapp.data

import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase

@Database(entities = [User::class], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {

    abstract fun userDao(): UserDao

    companion object {
        @Volatile
        private var INSTANCE: AppDatabase? = null

        fun getDatabase(context: Context): AppDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    AppDatabase::class.java,
                    "login_database"
                ).build()
                INSTANCE = instance
                instance
            }
        }
    }
}
MainActivity.kt
package com.example.loginapp

import android.content.Intent
import android.graphics.Color
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.example.loginapp.data.AppDatabase
import com.example.loginapp.databinding.ActivityMainBinding
import kotlinx.coroutines.launch

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    private lateinit var db: AppDatabase

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        db = AppDatabase.getDatabase(this)

        binding.btnLogin.setOnClickListener { doLogin() }
        binding.tvRegister.setOnClickListener {
            startActivity(Intent(this, RegisterActivity::class.java))
        }
    }

    private fun doLogin() {
        val username = binding.etUsername.text.toString().trim()
        val password = binding.etPassword.text.toString().trim()

        if (username.isEmpty()) {
            binding.tilUsername.error = "Username tidak boleh kosong"; return
        } else { binding.tilUsername.error = null }

        if (password.isEmpty()) {
            binding.tilPassword.error = "Password tidak boleh kosong"; return
        } else { binding.tilPassword.error = null }

        binding.btnLogin.isEnabled = false

        lifecycleScope.launch {
            val user = db.userDao().login(username, password)
            if (user != null) {
                showMessage("Login berhasil! Selamat datang, ${"{"}user.username{"}"}", isSuccess = true)
                val intent = Intent(this@MainActivity, HomeActivity::class.java)
                intent.putExtra("USERNAME", user.username)
                startActivity(intent)
                finish()
            } else {
                showMessage("Username atau password salah", isSuccess = false)
                binding.btnLogin.isEnabled = true
            }
        }
    }

    private fun showMessage(message: String, isSuccess: Boolean) {
        binding.tvMessage.apply {
            text = message
            setTextColor(if (isSuccess) Color.parseColor("#FF4CAF50") else Color.parseColor("#FFB00020"))
            visibility = View.VISIBLE
        }
    }
}
 Hasil Output
LoginApp — Android Studio · Pixel 6 API 34 · Login Gagal
Screenshot LoginApp - Pesan Login Gagal
LoginApp — Android Studio · Pixel 6 API 34 · Login Berhasil
Screenshot LoginApp - Pesan Login Berhasil

Komentar

Postingan populer dari blog ini

Pertemuan 4&5 PPB (B) - 25/03/2026

Pertemuan 2 PPB (B) - 04/03/2026

Pertemuan 7 - 08/04/2026