Skip to content

Instantly share code, notes, and snippets.

@Seniru
Created June 12, 2025 15:44
Show Gist options
  • Select an option

  • Save Seniru/5cb680f2a35d38ba8252d34f22cf45c8 to your computer and use it in GitHub Desktop.

Select an option

Save Seniru/5cb680f2a35d38ba8252d34f22cf45c8 to your computer and use it in GitHub Desktop.
Room database example. Please refer to my other gist related to todo items for stuff related with the RecyclerView (this is an updated version of that)
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
id("com.google.devtools.ksp")
}
android {
namespace = "com.seniru.recylerviewexample"
compileSdk = 35
defaultConfig {
applicationId = "com.seniru.recylerviewexample"
minSdk = 24
targetSdk = 35
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
}
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
implementation(libs.androidx.activity)
implementation(libs.androidx.constraintlayout)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
val room_version = "2.7.1"
implementation("androidx.room:room-runtime:$room_version")
// If this project uses any Kotlin source, use Kotlin Symbol Processing (KSP)
// See Add the KSP plugin to your project
ksp("androidx.room:room-compiler:$room_version")
}
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.kotlin.android) apply false
id("com.google.devtools.ksp") version "2.0.21-1.0.27" apply false
}
package com.seniru.recylerviewexample
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val newTodoText: TextView = findViewById(R.id.todoText)
val submitButton: Button = findViewById(R.id.submitButton)
val todoRepository = TodoRepository(TodoItemDatabase.getInstance(applicationContext))
// set up recycler view
val todoList: RecyclerView = findViewById(R.id.listView)
todoList.layoutManager = LinearLayoutManager(this)
val viewModel = ViewModelProvider(this)[MainActivityData::class.java]
CoroutineScope(Dispatchers.IO).launch {
val todoItems = todoRepository.getAll()
runOnUiThread {
viewModel.todoItems.value = todoItems
}
}
viewModel.todoItems.observe(this) {
if (viewModel.todoItems.value != null) {
todoList.adapter = TodoItemAdapter(viewModel.todoItems.value!!)
}
}
// add a to-do item to the list when submit button is clicked
submitButton.setOnClickListener {
CoroutineScope(Dispatchers.IO).launch {
todoRepository.insert(
TodoItem(description = newTodoText.text.toString(), completed = false)
)
// update to-do item list
val todoItems = todoRepository.getAll()
runOnUiThread {
viewModel.todoItems.value = todoItems
}
}
// notify the adapter of the newly added item so it can refresh the view
(todoList.adapter as TodoItemAdapter).notifyDataSetChanged()
}
}
}
package com.seniru.recylerviewexample
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class MainActivityData : ViewModel() {
private val _todoItems = MutableLiveData<List<TodoItem>>()
val todoItems = _todoItems
fun setData(list: List<TodoItem>) {
_todoItems.value = list
}
}
package com.seniru.recylerviewexample
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity
data class TodoItem(
@PrimaryKey(autoGenerate = true)
val id: Int? = null,
val description: String,
val completed: Boolean = false
)
package com.seniru.recylerviewexample
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
@Dao
interface TodoItemDao {
@Query("SELECT * FROM TodoItem")
fun getAll(): List<TodoItem>
@Insert
fun insert(todo: TodoItem)
}
package com.seniru.recylerviewexample
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
/**
* TodoItemDatabase uses a Singleton (as adviced in Google docs) design pattern to handle the database instance.
* Each RoomDatabase instance is fairly expensive, and you rarely need access to multiple instances within a single process.
* Please refer to the note in https://developer.android.com/training/data-storage/room for detailed information
*/
@Database(entities = [TodoItem::class], version = 1)
abstract class TodoItemDatabase : RoomDatabase() {
abstract fun getTodoDao(): TodoItemDao
companion object {
@Volatile
private var INSTANCE: TodoItemDatabase? = null
fun getInstance(context: Context): TodoItemDatabase {
synchronized(this) {
return INSTANCE ?: Room.databaseBuilder(
context.applicationContext,
TodoItemDatabase::class.java,
"todo_db"
).build().also {
INSTANCE = it
}
}
}
}
}
package com.seniru.recylerviewexample
class TodoRepository(
private val db: TodoItemDatabase
) {
suspend fun insert(todo: TodoItem) = db.getTodoDao().insert(todo)
// suspend fun delete(todo:TodoItem) = db.getTodoDao().deleteTodo(todo)
fun getAll(): List<TodoItem> = db.getTodoDao().getAll()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment