Artikel Teknologi

Insight engineering, security, dan pengembangan produk digital.

Kumpulan artikel praktis dari pengalaman lapangan, mulai dari server hardening, pengembangan web modern, hingga automation workflow.

Filter /crud-android-dengan-room-kotlin

Detail Artikel

Snippet 19 Sep 2025 851 views

CRUD Android dengan Room (Kotlin)

 

fitur:

  • Tampilkan data (RecyclerView + LiveData)

  • Tambah data (form input)

  • Edit data (klik item → buka form edit)

  • Hapus data (long click / tombol delete)


 

Tambahkan Dependency di build.gradle

dependencies {
    val room_version = "2.6.1" 

    implementation("androidx.room:room-runtime:$room_version")
    kapt("androidx.room:room-compiler:$room_version")
    implementation("androidx.room:room-ktx:$room_version")

    // ViewModel + LiveData
    implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.4")
    implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.8.4")
}

aktifkan viewBinding :


buildFeatures {
    viewBinding = true
}

aktifkan kapt :

plugins {
    id("kotlin-kapt")
}

 

 


  • Entity → mendefinisikan tabel

  • DAO → operasi CRUD

  • Database → singleton Room

  • Repository → penghubung DAO & ViewModel

  • ViewModel → pegang data lifecycle-aware

  • UI (RecyclerView) → tampilkan data


 


1. Struktur Project

app/
 └── java/com/example/roomcrud/
       ├── data/
       │    ├── Note.kt
       │    ├── NoteDao.kt
       │    ├── NoteDatabase.kt
       │    └── NoteRepository.kt
       ├── ui/
       │    ├── NoteViewModel.kt
       │    ├── NoteAdapter.kt
       │    ├── MainActivity.kt
       │    └── AddEditNoteActivity.kt
       └── ...

2. Entity: Note.kt

package com.example.roomcrud.data

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

@Entity(tableName = "notes")
data class Note(
    @PrimaryKey(autoGenerate = true) val id: Int = 0,
    val title: String,
    val content: String
)

3. DAO: NoteDao.kt

package com.example.roomcrud.data

import androidx.lifecycle.LiveData
import androidx.room.*

@Dao
interface NoteDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insert(note: Note)

    @Update
    suspend fun update(note: Note)

    @Delete
    suspend fun delete(note: Note)

    @Query("SELECT * FROM notes ORDER BY id DESC")
    fun getAllNotes(): LiveData<List<Note>>
}

4. Database: NoteDatabase.kt

package com.example.roomcrud.data

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

@Database(entities = [Note::class], version = 1, exportSchema = false)
abstract class NoteDatabase : RoomDatabase() {
    abstract fun noteDao(): NoteDao

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

        fun getDatabase(context: Context): NoteDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    NoteDatabase::class.java,
                    "note_database"
                ).build()
                INSTANCE = instance
                instance
            }
        }
    }
}

5. Repository: NoteRepository.kt

package com.example.roomcrud.data

class NoteRepository(private val noteDao: NoteDao) {
    val allNotes = noteDao.getAllNotes()

    suspend fun insert(note: Note) = noteDao.insert(note)
    suspend fun update(note: Note) = noteDao.update(note)
    suspend fun delete(note: Note) = noteDao.delete(note)
}

6. ViewModel: NoteViewModel.kt

package com.example.roomcrud.ui

import android.app.Application
import androidx.lifecycle.*
import com.example.roomcrud.data.*
import kotlinx.coroutines.launch

class NoteViewModel(application: Application) : AndroidViewModel(application) {
    private val repository: NoteRepository
    val allNotes: LiveData<List<Note>>

    init {
        val noteDao = NoteDatabase.getDatabase(application).noteDao()
        repository = NoteRepository(noteDao)
        allNotes = repository.allNotes
    }

    fun insert(note: Note) = viewModelScope.launch { repository.insert(note) }
    fun update(note: Note) = viewModelScope.launch { repository.update(note) }
    fun delete(note: Note) = viewModelScope.launch { repository.delete(note) }
}

7. Adapter: NoteAdapter.kt

package com.example.roomcrud.ui

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.roomcrud.data.Note
import com.example.roomcrud.databinding.ItemNoteBinding

class NoteAdapter(
    private val onEdit: (Note) -> Unit,
    private val onDelete: (Note) -> Unit
) : RecyclerView.Adapter<NoteAdapter.NoteViewHolder>() {

    private var notes = listOf<Note>()

    fun submitList(list: List<Note>) {
        notes = list
        notifyDataSetChanged()
    }

    class NoteViewHolder(val binding: ItemNoteBinding) : RecyclerView.ViewHolder(binding.root)

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoteViewHolder {
        val binding = ItemNoteBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return NoteViewHolder(binding)
    }

    override fun onBindViewHolder(holder: NoteViewHolder, position: Int) {
        val note = notes[position]
        holder.binding.tvTitle.text = note.title
        holder.binding.tvContent.text = note.content

        holder.binding.root.setOnClickListener { onEdit(note) }
        holder.binding.root.setOnLongClickListener {
            onDelete(note)
            true
        }
    }

    override fun getItemCount(): Int = notes.size
}

8. Layout Item: item_note.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:padding="12dp"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/tvTitle"
        android:textStyle="bold"
        android:textSize="18sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/tvContent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

9. MainActivity: MainActivity.kt

package com.example.roomcrud.ui

import android.content.Intent
import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import com.example.roomcrud.data.Note
import com.example.roomcrud.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    private val viewModel: NoteViewModel by viewModels()
    private lateinit var adapter: NoteAdapter

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

        adapter = NoteAdapter(
            onEdit = { note ->
                val intent = Intent(this, AddEditNoteActivity::class.java)
                intent.putExtra("note_id", note.id)
                intent.putExtra("note_title", note.title)
                intent.putExtra("note_content", note.content)
                startActivity(intent)
            },
            onDelete = { note ->
                viewModel.delete(note)
            }
        )
        binding.recyclerView.adapter = adapter
        binding.recyclerView.layoutManager = LinearLayoutManager(this)

        viewModel.allNotes.observe(this) { notes ->
            adapter.submitList(notes)
        }

        binding.fabAdd.setOnClickListener {
            startActivity(Intent(this, AddEditNoteActivity::class.java))
        }
    }
}

10. Activity Form: AddEditNoteActivity.kt

package com.example.roomcrud.ui

import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import com.example.roomcrud.data.Note
import com.example.roomcrud.databinding.ActivityAddEditNoteBinding

class AddEditNoteActivity : AppCompatActivity() {
    private lateinit var binding: ActivityAddEditNoteBinding
    private val viewModel: NoteViewModel by viewModels()
    private var noteId: Int? = null

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

        noteId = intent.getIntExtra("note_id", -1).takeIf { it != -1 }
        val oldTitle = intent.getStringExtra("note_title") ?: ""
        val oldContent = intent.getStringExtra("note_content") ?: ""

        binding.etTitle.setText(oldTitle)
        binding.etContent.setText(oldContent)

        binding.btnSave.setOnClickListener {
            val note = Note(
                id = noteId ?: 0,
                title = binding.etTitle.text.toString(),
                content = binding.etContent.text.toString()
            )
            if (noteId == null) {
                viewModel.insert(note)
            } else {
                viewModel.update(note)
            }
            finish()
        }
    }
}

11. Layout Main: activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/fabAdd"
        android:src="@android:drawable/ic_input_add"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="end"
        android:layout_margin="16dp" />
</LinearLayout>

12. Layout Form: activity_add_edit_note.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:padding="16dp"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <EditText
        android:id="@+id/etTitle"
        android:hint="Judul"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <EditText
        android:id="@+id/etContent"
        android:hint="Isi Catatan"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:minLines="4" />

    <Button
        android:id="@+id/btnSave"
        android:text="Simpan"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

 

Artikel Terbaru

Konten pilihan untuk pengembangan skill

Materi disusun ringkas dan aplikatif agar bisa langsung Anda praktikkan.

Fix Zima VM Web Console via Cloudflare Tunnel Using NGINX Stream (Port 5700)
Note 07 Apr 2026

Fix Zima VM Web Console via Cloudflare Tunnel Using NGINX Stream (Port 5700)

Solusi untuk error WebSocket Zima VM melalui Cloudflare Tunnel menggunakan NGINX Stream (port 5700).

Buka Detail
Mengakses Server SSH Melalui Cloudflare Tunnel dengan Port Forwarding PostgreSQL
Note 09 Mar 2026

Mengakses Server SSH Melalui Cloudflare Tunnel dengan Port Forwarding PostgreSQL

Cara menggunakan SSH melalui Cloudflare Access sekaligus membuat port forwarding ke database PostgreSQL menggunakan konfigurasi ~/.ssh/config.

Buka Detail
Flutter Super App untuk Portal & Learning Management System
Portfolio 07 Mar 2026

Flutter Super App untuk Portal & Learning Management System

Fahram Mobile App adalah aplikasi mobile berbasis Flutter yang mengintegrasikan dua platform web utama: Portal Fahram – portal publik berisi artikel, galeri, dokumen, dan...

Buka Detail
LMS Web Platform
Portfolio 06 Mar 2026

LMS Web Platform

Fahram LMS adalah platform Learning Management System berbasis web yang dirancang untuk menyediakan pengalaman belajar digital yang modern, interaktif, dan mudah digunaka...

Buka Detail
Gratis Email Bisnis dengan Custom Domain
Services 05 Mar 2026

Gratis Email Bisnis dengan Custom Domain

Email custom domain adalah alamat email yang menggunakan nama domain bisnis Anda sendiri, bukan domain penyedia email gratis. Contoh perbandingan: Email biasa namabisni...

Buka Detail
Jasa Pembuatan Website Murah Profesional Mulai Rp500.000
Services 05 Mar 2026

Jasa Pembuatan Website Murah Profesional Mulai Rp500.000

Mulai Website Bisnis Anda Sekarang Jangan biarkan bisnis Anda tertinggal di era digital. Dengan investasi yang sangat terjangkau, Anda sudah bisa memiliki website profesi...

Buka Detail
Sistem Informasi Gudang & Aset Manajemen Terintegrasi
Portfolio 23 Feb 2026

Sistem Informasi Gudang & Aset Manajemen Terintegrasi

Kelola stok barang, aset perusahaan, penyusutan, mutasi, hingga audit log dalam satu platform terpusat. SIGAM dirancang untuk organisasi yang membutuhkan kontrol inventar...

Buka Detail
Portal Website Polres Cilegon
Portfolio 01 Jan 2026

Portal Website Polres Cilegon

Polres Cilegon adalah website resmi Kepolisian Resor Cilegon - bagian dari Kepolisian Negara Republik Indonesia (Polri) yang bertugas menjaga keamanan, ketertiban, dan pe...

Buka Detail
Sistem Manajemen Email Kampus
Portfolio 26 Jun 2025

Sistem Manajemen Email Kampus

Platform untuk otomatis membuat dan mengelola akun email mahasiswa/dosen pada Google Workspace atau Microsoft 365. Fitur utama mencakup pendaftaran, approval admin, provi...

Buka Detail
Buku Pemrograman web dengan PHP framework Laravel
Buku 25 Jul 2023

Buku Pemrograman web dengan PHP framework Laravel

Buku ini dirancang untuk pemula yang ingin mempelajari dasar-dasar pemrograman web menggunakan PHP dan juga bagi mereka yang ingin menguasai Laravel, framework PHP yang s...

Buka Detail
Kampus Komputer Cilegon Banten
Schools 15 Mar 2010

Kampus Komputer Cilegon Banten

- Nama Perguruan Tinggi Politeknik PIKSI Input Website https://piksiinputserang.ac.id/ Prodi Ilmu Komputer D4 - Rekayasa Keamanan Siber, D3 - Manajemen Inform...

Buka Detail
MINI SIEM - Solusi Monitoring Log & Deteksi Ancaman Real-Time untuk Infrastruktur Anda
Portfolio 25 Feb 2026

MINI SIEM - Solusi Monitoring Log & Deteksi Ancaman Real-Time untuk Infrastruktur Anda

Kelola log server, deteksi anomali, dan respon insiden keamanan dalam satu dashboard terpusat. Mini SIEM dirancang untuk organisasi yang membutuhkan visibilitas penuh ter...

Buka Detail