Jetpack Compose has revolutionized Android UI development, offering a modern, declarative approach to building user interfaces. Combining this with Room’s robust database capabilities and Hilt’s seamless dependency injection creates a powerful trifecta for scalable, maintainable, and testable Android applications. In this guide, we’ll explore how to integrate Room with Hilt in a Jetpack Compose application, ensuring best practices and performance optimization throughout.
Prerequisites
Before diving in, ensure you have the following:
A basic understanding of Jetpack Compose, Room, and Hilt.
Android Studio Flamingo or higher.
Kotlin version 1.9 or later.
If you're not familiar with the basics of these technologies, consider reviewing the official documentation for Jetpack Compose, Room, and Hilt.
Step 1: Adding Dependencies
To get started, include the necessary dependencies in your build.gradle
(or build.gradle.kts
) file:
// Jetpack Compose dependencies
implementation "androidx.compose.ui:ui:1.5.0"
implementation "androidx.compose.material:material:1.5.0"
implementation "androidx.compose.ui:ui-tooling-preview:1.5.0"
kapt "androidx.compose.ui:ui-tooling:1.5.0"
// Room dependencies
implementation "androidx.room:room-runtime:2.5.2"
kapt "androidx.room:room-compiler:2.5.2"
implementation "androidx.room:room-ktx:2.5.2"
// Hilt dependencies
implementation "com.google.dagger:hilt-android:2.50"
kapt "com.google.dagger:hilt-android-compiler:2.50"
// Hilt Compose integration
implementation "androidx.hilt:hilt-navigation-compose:1.1.0"
Synchronize your project to ensure all dependencies are downloaded.
Step 2: Setting Up Room
Define Your Entity
Room requires entity classes to define database tables. Here’s an example:
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
)
Create the DAO
Define the data access object (DAO) for querying the database:
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
@Dao
interface NoteDao {
@Query("SELECT * FROM notes")
suspend fun getAllNotes(): List<Note>
@Insert
suspend fun insert(note: Note)
}
Setup the Database
Create the Room database class:
import androidx.room.Database
import androidx.room.RoomDatabase
@Database(entities = [Note::class], version = 1)
abstract class NoteDatabase : RoomDatabase() {
abstract fun noteDao(): NoteDao
}
Step 3: Configuring Hilt
Hilt simplifies dependency injection, making it easy to provide instances of Room components.
Application Class
Add the @HiltAndroidApp
annotation to your Application
class:
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
class MyApplication : Application()
Module for Room
Create a Hilt module to provide Room dependencies:
import android.content.Context
import androidx.room.Room
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.components.SingletonComponent
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
object DatabaseModule {
@Provides
@Singleton
fun provideDatabase(@ApplicationContext context: Context): NoteDatabase {
return Room.databaseBuilder(
context,
NoteDatabase::class.java,
"note_database"
).build()
}
@Provides
fun provideNoteDao(database: NoteDatabase): NoteDao {
return database.noteDao()
}
}
Step 4: Building the UI with Jetpack Compose
With Room and Hilt configured, let’s create a Compose-based UI to display and interact with the data.
ViewModel
Use Hilt to inject dependencies into a ViewModel:
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class NoteViewModel @Inject constructor(
private val noteDao: NoteDao
) : ViewModel() {
val notes = mutableStateOf<List<Note>>(emptyList())
fun fetchNotes() {
viewModelScope.launch {
notes.value = noteDao.getAllNotes()
}
}
fun addNote(note: Note) {
viewModelScope.launch {
noteDao.insert(note)
fetchNotes()
}
}
}
Composable Function
Build a Composable UI to display notes:
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
@Composable
fun NoteScreen() {
val viewModel: NoteViewModel = hiltViewModel()
val notes by viewModel.notes.collectAsState()
var title by remember { mutableStateOf("") }
var content by remember { mutableStateOf("") }
Column(modifier = Modifier.padding(16.dp)) {
BasicTextField(
value = title,
onValueChange = { title = it },
modifier = Modifier.fillMaxWidth().padding(8.dp),
singleLine = true
)
BasicTextField(
value = content,
onValueChange = { content = it },
modifier = Modifier.fillMaxWidth().padding(8.dp)
)
Button(onClick = {
viewModel.addNote(Note(title = title, content = content))
title = ""
content = ""
}) {
Text("Add Note")
}
LazyColumn {
items(notes) { note ->
Text("${note.title}: ${note.content}")
}
}
}
}
Best Practices
Avoid Blocking Main Thread: Always use
suspend
functions for Room database operations.State Management: Use
State
orFlow
with Compose to manage and observe UI state effectively.Testing: Write unit tests for your DAOs and UI tests for Compose screens.
Dependency Injection: Leverage Hilt’s modular approach to keep code maintainable and scalable.
Conclusion
Integrating Room with Hilt in Jetpack Compose applications is a straightforward process that offers clean architecture, improved scalability, and better testability. By following the practices outlined in this guide, you’ll be able to create performant and maintainable Android apps with ease.
Remember to keep your dependencies up-to-date and continuously refine your architecture to meet the evolving needs of your projects.