1. Dasar Pemrograman Kotlin
Kotlin adalah bahasa pemrograman modern yang dikembangkan oleh JetBrains dan menjadi bahasa utama untuk pengembangan Android sejak Google mengumumkannya sebagai "first-class language" untuk Android pada tahun 2019. Kotlin 100% interoperable dengan Java, memiliki sintaks yang lebih ringkas, dan menghilangkan banyak boilerplate code.
Mengapa Kotlin untuk Android?
| Keunggulan | Penjelasan |
|---|---|
| Null Safety | Sistem tipe nullable/non-nullable yang mencegah NullPointerException di compile-time |
| Concise Syntax | Lebih ringkas dari Java — data class, extension functions, lambda |
| Coroutines | Async programming yang elegan tanpa callback hell |
| Java Interop | Bisa menggunakan semua library Java yang sudah ada |
| Google Support | Direkomendasikan Google, semua library Jetpack mendukung Kotlin-first |
| Smart Casts | Automatic type casting setelah null check |
Variabel & Tipe Data
// ===== VARIABEL ===== val nama: String = "BeebaneLabs" // Immutable (tidak bisa diubah) var umur: Int = 25 // Mutable (bisa diubah) // Type inference — tipe di-inferensi otomatis val kota = "Jakarta" // String val populasi = 10_000_000 // Int (underscore untuk readability) val tinggi = 175.5 // Double val isActive = true // Boolean // Nullable types var alamat: String? = null // Bisa null dengan ? var namaLengkap: String = "Budi" // Tidak bisa null // Safe call operator ?. dan Elvis operator ?: val panjang = alamat?.length ?: 0 // Jika null, hasilnya 0 // ===== TIPE DATA DASAR ===== val angka: Byte = 127 // 8-bit val angka2: Short = 32767 // 16-bit val angka3: Int = 2147483647 // 32-bit val angka4: Long = 9_223_372_036_854_775_807 // 64-bit val desimal: Float = 3.14f // 32-bit val desimal2: Double = 3.14159265 // 64-bit val huruf: Char = 'A' // Single character val teks: String = "Hello Kotlin" // String
Function & Lambda
// Function biasa
fun tambah(a: Int, b: Int): Int {
return a + b
}
// Single-expression function
fun kali(a: Int, b: Int): Int = a * b
// Default parameters & named arguments
fun sapa(nama: String, pesan: String = "Halo"): String {
return "$pesan, $nama!"
}
// sapa("Budi") → "Halo, Budi!"
// sapa("Budi", pesan="Hey") → "Hey, Budi!"
// Extension function
fun String.kebalikan(): String = this.reversed()
// "Hello".kebalikan() → "olleH"
// Lambda
val kuadrat = { x: Int -> x * x }
val list = listOf(1, 2, 3, 4, 5)
val genap = list.filter { it % 2 == 0 }
val hasil = list.map { it * 2 }
// Higher-order function
fun operasi(a: Int, b: Int, op: (Int, Int) -> Int): Int {
return op(a, b)
}
val hasilTambah = operasi(5, 3) { x, y -> x + y }
// Coroutines — async
suspend fun fetchData(): String {
delay(1000) // Non-blocking delay
return "Data dari server"
}
Class & Data Class
// Class biasa
class Mahasiswa(val nama: String, var umur: Int) {
var jurusan: String = "Teknik Informatika"
init {
println("Mahasiswa $nama dibuat")
}
fun perkenalkan() {
println("Halo, saya $nama, umur $umur, jurusan $jurusan")
}
}
// Data class — otomatis mendapat equals, hashCode, toString, copy
data class Produk(
val id: Int,
val nama: String,
val harga: Int,
val stok: Int = 0
)
val laptop = Produk(1, "ASUS ROG", 15000000, 10)
val laptopBaru = laptop.copy(harga = 13000000, stok = 5)
println(laptop) // Produk(id=1, nama=ASUS ROG, harga=15000000, stok=10)
// Sealed class — untuk representasi tipe yang terbatas
sealed class Hasil<out T>
class Sukses<T>(val data: T) : Hasil<T>()
class Error(val pesan: String) : Hasil<Nothing>()
class Loading : Hasil<Nothing>()
fun handleHasil(hasil: Hasil<String>) {
when (hasil) {
is Sukses -> println("Data: ${hasil.data}")
is Error -> println("Error: ${hasil.pesan}")
is Loading -> println("Loading...")
}
}
2. Setup Android Studio
Android Studio adalah IDE resmi untuk pengembangan Android, berdasarkan IntelliJ IDEA. Android Studio menyediakan semua tools yang dibutuhkan: editor kode, visual layout editor, emulator, debugger, dan profiler.
Langkah Instalasi
# 1. Download Android Studio dari https://developer.android.com/studio # Versi terbaru: Android Studio Ladybug (2024.2) # 2. Instal Android Studio (wizard akan memandu) # - Instal Android SDK # - Instal Android Virtual Device (AVD) # - Instal SDK Build Tools # 3. Setelah instalasi, buka SDK Manager: # File → Settings → Appearance → System Settings → Android SDK # - SDK Platforms: Android 14 (API 34) atau terbaru # - SDK Tools: Android SDK Build-Tools, CMake, NDK # 4. Buat AVD (Android Virtual Device): # Tools → Device Manager → Create Device # - Pilih device (misal Pixel 8) # - Pilih system image (API 34) # - Finish # 5. Buat proyek baru: # File → New → New Project # - Template: Empty Activity (Compose) atau Empty Views Activity # - Language: Kotlin # - Minimum SDK: API 24 (Android 7.0) # - Build system: Gradle (Kotlin DSL)
Struktur Proyek Android
MyAndroidApp/ ├── app/ │ ├── src/ │ │ ├── main/ │ │ │ ├── java/com/example/myapp/ │ │ │ │ ├── MainActivity.kt ← Entry point │ │ │ │ ├── ui/ ← UI components │ │ │ │ │ ├── theme/ │ │ │ │ │ └── screens/ │ │ │ │ ├── data/ ← Data layer │ │ │ │ │ ├── local/ ← Room database │ │ │ │ │ └── remote/ ← API service │ │ │ │ └── model/ ← Data models │ │ │ ├── res/ ← Resources │ │ │ │ ├── layout/ ← XML layouts (Views) │ │ │ │ ├── values/ ← strings, colors, themes │ │ │ │ ├── drawable/ ← Gambar, shapes │ │ │ │ └── mipmap/ ← App icons │ │ │ └── AndroidManifest.xml ← Konfigurasi app │ │ └── test/ ← Unit tests │ └── build.gradle.kts ← Konfigurasi build app ├── gradle/ ├── build.gradle.kts ← Konfigurasi build root ├── settings.gradle.kts └── gradle.properties
Android Studio terbaru menggunakan build.gradle.kts (Kotlin DSL) sebagai pengganti build.gradle (Groovy). Kotlin DSL memberikan autocompletion yang lebih baik dan type-safety saat mengonfigurasi dependencies. Pastikan untuk selalu Sync Project setelah mengubah file Gradle.
3. Activities & Lifecycle
Activity adalah komponen fundamental Android yang merepresentasikan satu layar. Setiap Activity memiliki lifecycle yang dikelola oleh sistem Android — memahami lifecycle ini sangat penting untuk mengelola resource dengan benar.
onCreate()
│
▼
onStart()
│
▼
onResume() ◄──────────────┐
│ │
▼ │
[Activity Running] │
│ │
▼ │
onPause() │
│ │
▼ │
onStop() │
│ onRestart()│
▼ │
onDestroy() │
User kembali → onStart() ───────┘
Activity Dasar
package com.example.myapp
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
companion object {
private const val TAG = "MainActivity"
}
// View references
private lateinit var tvGreeting: TextView
private lateinit var btnNavigate: Button
// ===== LIFECYCLE METHODS =====
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) // Set layout XML
Log.d(TAG, "onCreate")
// Inisialisasi views
tvGreeting = findViewById(R.id.tvGreeting)
btnNavigate = findViewById(R.id.btnNavigate)
// Set teks
tvGreeting.text = "Selamat Datang di Aplikasi Android!"
// Navigasi ke Activity lain
btnNavigate.setOnClickListener {
val intent = Intent(this, DetailActivity::class.java).apply {
putExtra("ITEM_ID", 42)
putExtra("ITEM_NAME", "Produk Kotlin")
}
startActivity(intent)
}
}
override fun onStart() {
super.onStart()
Log.d(TAG, "onStart — Activity terlihat")
}
override fun onResume() {
super.onResume()
Log.d(TAG, "onResume — Activity berinteraksi")
}
override fun onPause() {
super.onPause()
Log.d(TAG, "onPause — Activity terhalang sebagian")
}
override fun onStop() {
super.onStop()
Log.d(TAG, "onStop — Activity tidak terlihat")
}
override fun onDestroy() {
super.onDestroy()
Log.d(TAG, "onDestroy — Activity dihancurkan")
}
}
Menerima Data dari Activity Lain
package com.example.myapp
import android.os.Bundle
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
class DetailActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_detail)
// Menerima data dari Intent
val itemId = intent.getIntExtra("ITEM_ID", -1)
val itemName = intent.getStringExtra("ITEM_NAME") ?: "Unknown"
val tvDetail: TextView = findViewById(R.id.tvDetail)
tvDetail.text = "ID: $itemId\nNama: $itemName"
// Enable back button di action bar
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.title = itemName
}
override fun onSupportNavigateUp(): Boolean {
finish() // Kembali ke Activity sebelumnya
return true
}
}
XML Layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="24dp"
android:background="#FAFAFA">
<TextView
android:id="@+id/tvGreeting"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Halo, Android!"
android:textSize="24sp"
android:textStyle="bold"
android:textColor="#333333"
android:layout_marginBottom="16dp" />
<EditText
android:id="@+id/etInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Ketik sesuatu..."
android:padding="12dp"
android:background="@drawable/edit_text_bg"
android:layout_marginBottom="16dp" />
<Button
android:id="@+id/btnNavigate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Buka Detail"
android:backgroundTint="#2196F3"
android:textColor="#FFFFFF"
android:padding="12dp" />
</LinearLayout>
4. Fragments & Multi-Screen
Fragment adalah komponen UI yang bisa digunakan kembali di dalam Activity. Fragments memungkinkan desain modular yang bisa beradaptasi dengan berbagai ukuran layar (phone vs tablet).
package com.example.myapp.ui
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
import androidx.fragment.app.Fragment
import com.example.myapp.R
class HomeFragment : Fragment() {
private var paramNama: String? = null
companion object {
fun newInstance(nama: String): HomeFragment {
val fragment = HomeFragment()
val args = Bundle().apply {
putString("NAMA", nama)
}
fragment.arguments = args
return fragment
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
paramNama = arguments?.getString("NAMA") ?: "Pengguna"
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_home, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val tvWelcome: TextView = view.findViewById(R.id.tvWelcome)
val btnToProfile: Button = view.findViewById(R.id.btnToProfile)
tvWelcome.text = "Selamat datang, $paramNama!"
btnToProfile.setOnClickListener {
parentFragmentManager.beginTransaction()
.replace(R.id.fragmentContainer, ProfileFragment())
.addToBackStack(null)
.commit()
}
}
}
Bottom Navigation dengan Fragments
package com.example.myapp
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import com.google.android.material.bottomnavigation.BottomNavigationView
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val bottomNav: BottomNavigationView = findViewById(R.id.bottomNav)
// Load fragment awal
if (savedInstanceState == null) {
loadFragment(HomeFragment())
}
bottomNav.setOnItemSelectedListener { item ->
val fragment: Fragment = when (item.itemId) {
R.id.nav_home -> HomeFragment()
R.id.nav_search -> SearchFragment()
R.id.nav_profile -> ProfileFragment()
else -> HomeFragment()
}
loadFragment(fragment)
true
}
}
private fun loadFragment(fragment: Fragment) {
supportFragmentManager.beginTransaction()
.replace(R.id.fragmentContainer, fragment)
.commit()
}
}
5. RecyclerView & Adapters
RecyclerView adalah komponen untuk menampilkan daftar data yang panjang secara efisien. RecyclerView hanya me-render item yang terlihat di layar dan mendaur ulang view yang sudah tidak terlihat.
Data Model
// Model data
data class Artikel(
val id: Int,
val judul: String,
val deskripsi: String,
val gambarUrl: String,
val tanggal: String
)
Adapter & ViewHolder
package com.example.myapp.adapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.myapp.R
import com.example.myapp.model.Artikel
class ArtikelAdapter(
private val onItemClick: (Artikel) -> Unit
) : ListAdapter<Artikel, ArtikelAdapter.ArtikelViewHolder>(ArtikelDiffCallback()) {
// ViewHolder — menyimpan referensi ke view
class ArtikelViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val tvJudul: TextView = itemView.findViewById(R.id.tvJudul)
val tvDeskripsi: TextView = itemView.findViewById(R.id.tvDeskripsi)
val tvTanggal: TextView = itemView.findViewById(R.id.tvTanggal)
val imgArtikel: ImageView = itemView.findViewById(R.id.imgArtikel)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ArtikelViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_artikel, parent, false)
return ArtikelViewHolder(view)
}
override fun onBindViewHolder(holder: ArtikelViewHolder, position: Int) {
val artikel = getItem(position)
holder.tvJudul.text = artikel.judul
holder.tvDeskripsi.text = artikel.deskripsi
holder.tvTanggal.text = artikel.tanggal
// Load image dengan Glide/Coil
// Glide.with(holder.itemView.context)
// .load(artikel.gambarUrl)
// .into(holder.imgArtikel)
holder.itemView.setOnClickListener {
onItemClick(artikel)
}
}
}
// DiffUtil — efisien membandingkan list lama vs baru
class ArtikelDiffCallback : DiffUtil.ItemCallback<Artikel>() {
override fun areItemsTheSame(oldItem: Artikel, newItem: Artikel) =
oldItem.id == newItem.id
override fun areContentsTheSame(oldItem: Artikel, newItem: Artikel) =
oldItem == newItem
}
Menggunakan RecyclerView di Fragment
class ArtikelListFragment : Fragment() {
private lateinit var recyclerView: RecyclerView
private lateinit var adapter: ArtikelAdapter
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_artikel_list, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
recyclerView = view.findViewById(R.id.rvArtikel)
adapter = ArtikelAdapter { artikel ->
// Handle click — navigasi ke detail
Toast.makeText(context, "Klik: ${artikel.judul}", Toast.LENGTH_SHORT).show()
}
recyclerView.apply {
layoutManager = LinearLayoutManager(context)
adapter = this@ArtikelListFragment.adapter
setHasFixedSize(true)
}
// Submit data
val dataDummy = listOf(
Artikel(1, "Belajar Kotlin", "Dasar-dasar Kotlin", "", "25 Jun 2026"),
Artikel(2, "Android Studio", "Setup & konfigurasi", "", "24 Jun 2026"),
Artikel(3, "Jetpack Compose", "UI modern Android", "", "23 Jun 2026"),
)
adapter.submitList(dataDummy)
}
}
6. Room Database
Room adalah library dari Android Jetpack yang menyediakan abstraksi di atas SQLite. Room memberikan compile-time SQL verification, type-safe queries, dan integrasi yang baik dengan LiveData/Flow.
Setup Dependencies
dependencies {
// Room Database
val roomVersion = "2.6.1"
implementation("androidx.room:room-runtime:$roomVersion")
implementation("androidx.room:room-ktx:$roomVersion") // Coroutines support
kapt("androidx.room:room-compiler:$roomVersion") // Annotation processor
// ViewModel & LiveData
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0")
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.7.0")
}
Entity, DAO, Database
package com.example.myapp.data
import androidx.lifecycle.LiveData
import androidx.room.*
// ===== ENTITY =====
@Entity(tableName = "catatan")
data class Catatan(
@PrimaryKey(autoGenerate = true)
val id: Int = 0,
@ColumnInfo(name = "judul")
val judul: String,
@ColumnInfo(name = "isi")
val isi: String,
@ColumnInfo(name = "tanggal")
val tanggal: Long = System.currentTimeMillis(),
@ColumnInfo(name = "favorit")
val favorit: Boolean = false
)
// ===== DAO (Data Access Object) =====
@Dao
interface CatatanDao {
@Query("SELECT * FROM catatan ORDER BY tanggal DESC")
fun getAll(): LiveData<List<Catatan>>
@Query("SELECT * FROM catatan WHERE id = :id")
suspend fun getById(id: Int): Catatan?
@Query("SELECT * FROM catatan WHERE judul LIKE '%' || :query || '%'")
fun search(query: String): LiveData<List<Catatan>>
@Query("SELECT * FROM catatan WHERE favorit = 1")
fun getFavorites(): LiveData<List<Catatan>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(catatan: Catatan)
@Update
suspend fun update(catatan: Catatan)
@Delete
suspend fun delete(catatan: Catatan)
@Query("DELETE FROM catatan")
suspend fun deleteAll()
}
// ===== DATABASE =====
@Database(entities = [Catatan::class], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
abstract fun catatanDao(): CatatanDao
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,
"app_database"
).build()
INSTANCE = instance
instance
}
}
}
}
ViewModel dengan Room
package com.example.myapp.ui
import android.app.Application
import androidx.lifecycle.*
import com.example.myapp.data.AppDatabase
import com.example.myapp.data.Catatan
import kotlinx.coroutines.launch
class CatatanViewModel(application: Application) : AndroidViewModel(application) {
private val dao = AppDatabase.getDatabase(application).catatanDao()
// LiveData — otomatis update UI saat data berubah
val semuaCatatan: LiveData<List<Catatan>> = dao.getAll()
val favoritCatatan: LiveData<List<Catatan>> = dao.getFavorites()
private val _searchQuery = MutableLiveData<String>("")
val searchResults: LiveData<List<Catatan>> = _searchQuery.switchMap { query ->
if (query.isBlank()) dao.getAll()
else dao.search(query)
}
fun tambah(judul: String, isi: String) {
viewModelScope.launch {
dao.insert(Catatan(judul = judul, isi = isi))
}
}
fun hapus(catatan: Catatan) {
viewModelScope.launch {
dao.delete(catatan)
}
}
fun toggleFavorit(catatan: Catatan) {
viewModelScope.launch {
dao.update(catatan.copy(favorit = !catatan.favorit))
}
}
fun search(query: String) {
_searchQuery.value = query
}
}
7. Pengenalan Jetpack Compose
Jetpack Compose adalah toolkit UI modern Android yang menggunakan pendekatan declarative — mirip Flutter dan React Native. Compose menggantikan XML layouts dengan kode Kotlin yang lebih fleksibel dan type-safe.
Compose vs XML Views
| Aspek | Jetpack Compose | XML Views |
|---|---|---|
| Pendekatan | Declarative (Kotlin DSL) | Imperative (XML) |
| State Management | Built-in (State, remember) | Manual (setText, dll) |
| Preview | @Preview annotation | Layout Editor visual |
| Reusability | Composable functions | Custom Views / Includes |
| Performance | Smart recomposition | Manual optimization |
| Learning Curve | Mudah (jika tahu Kotlin) | Sedang (XML + Java/Kotlin) |
Composable Dasar
package com.example.myapp.ui
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
// ===== COMPOSABLE FUNCTION =====
@Composable
fun GreetingScreen() {
// State — otomatis recompose saat berubah
var nama by remember { mutableStateOf("") }
var sapaan by remember { mutableStateOf("") }
Column(
modifier = Modifier
.fillMaxSize()
.padding(24.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "Halo, Jetpack Compose!",
style = MaterialTheme.typography.headlineMedium,
color = MaterialTheme.colorScheme.primary
)
Spacer(modifier = Modifier.height(16.dp))
// Input field
OutlinedTextField(
value = nama,
onValueChange = { nama = it },
label = { Text("Nama Anda") },
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
// Button
Button(
onClick = { sapaan = "Halo, $nama! 👋" },
modifier = Modifier.fillMaxWidth(),
enabled = nama.isNotBlank()
) {
Text("Sapa!")
}
Spacer(modifier = Modifier.height(16.dp))
// Hasil
if (sapaan.isNotEmpty()) {
Card(
modifier = Modifier.fillMaxWidth(),
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.primaryContainer
)
) {
Text(
text = sapaan,
modifier = Modifier.padding(16.dp),
style = MaterialTheme.typography.bodyLarge
)
}
}
}
}
LazyColumn (List di Compose)
// Data model
data class Item(val id: Int, val nama: String, val harga: Int)
@Composable
fun ItemListScreen() {
val items = remember {
listOf(
Item(1, "Laptop ASUS", 12000000),
Item(2, "Keyboard Mekanik", 850000),
Item(3, "Monitor 27\"", 4500000),
Item(4, "Mouse Logitech", 350000),
)
}
LazyColumn(
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
items(items) { item ->
Card(
modifier = Modifier.fillMaxWidth()
) {
Row(
modifier = Modifier
.padding(16.dp)
.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Column {
Text(
text = item.nama,
style = MaterialTheme.typography.titleMedium
)
Text(
text = "Rp ${item.harga.toLocaleString()}",
color = MaterialTheme.colorScheme.primary,
style = MaterialTheme.typography.bodyMedium
)
}
Button(onClick = { /* Tambah ke keranjang */ }) {
Text("Beli")
}
}
}
}
}
}
// Entry point Activity
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MaterialTheme {
Surface(modifier = Modifier.fillMaxSize()) {
ItemListScreen()
}
}
}
}
}
Untuk proyek baru, Google merekomendasikan langsung menggunakan Jetpack Compose. Compose adalah masa depan Android UI development — semua library Jetpack baru sudah Compose-first. Namun, masih banyak codebase lama yang menggunakan XML Views, jadi penting untuk mengenal keduanya.
8. Quiz: Uji Pemahamanmu!
Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang Android Development dengan Kotlin: