When developing Android applications, data persistence is a crucial aspect that developers need to handle efficiently. One of the most robust solutions for database management in Android is the Room Persistence Library, a part of Android Jetpack. Room provides an abstraction layer over SQLite, allowing for more robust database access while harnessing the full power of SQLite. This guide will walk you through setting up Room in your Android project using Kotlin.

Introduction to Room

Room is designed to simplify database interactions and reduce boilerplate code. It provides compile-time checks of SQLite statements, ensuring that your queries are validated at compile time rather than runtime. Room also supports LiveData and RxJava, making it easier to work with reactive programming models.

Key Components of Room

  • Entity: Represents a table within the database. Each entity is a class annotated with @Entity.
  • DAO (Data Access Object): An interface that provides methods to interact with the database. DAOs are annotated with @Dao.
  • Database: The main access point to the database, annotated with @Database. It holds the database and serves as the main connection to your app's persisted data.

Setting Up Room in Your Android Project

To start using Room, you need to add the necessary dependencies to your project. Here’s a step-by-step guide:

Step 1: Add Room Dependencies

Open your build.gradle file at the app level and add the following dependencies:

dependencies {
    def room_version = "2.5.1"
    implementation "androidx.room:room-runtime:$room_version"
    kapt "androidx.room:room-compiler:$room_version"
    // optional - Kotlin Extensions and Coroutines support for Room
    implementation "androidx.room:room-ktx:$room_version"
}

Make sure to apply the Kotlin KAPT plugin at the top of your build.gradle file:

apply plugin: 'kotlin-kapt'

Step 2: Define an Entity

Create a data class that represents an entity in your database. For example, if we are dealing with a user database, we can define a User entity as follows:

@Entity(tableName = "users")
data class User(
    @PrimaryKey(autoGenerate = true) val id: Int = 0,
    @ColumnInfo(name = "first_name") val firstName: String,
    @ColumnInfo(name = "last_name") val lastName: String,
    val age: Int
)

In this example, the User class is annotated with @Entity, indicating that it is a table in the database. The @PrimaryKey annotation is used to define the primary key, and @ColumnInfo is used to specify custom column names.

Step 3: Create a DAO

Next, create a DAO interface to define methods for accessing the database. Here’s an example DAO for the User entity:

@Dao
interface UserDao {
    @Insert
    suspend fun insert(user: User)

    @Update
    suspend fun update(user: User)

    @Delete
    suspend fun delete(user: User)

    @Query("SELECT * FROM users WHERE id = :userId")
    suspend fun getUserById(userId: Int): User?

    @Query("SELECT * FROM users")
    fun getAllUsers(): LiveData>
}

The UserDao interface provides methods for inserting, updating, and deleting users, as well as querying the database. Note the use of the @Query annotation for custom SQL queries.

Step 4: Create the Database

Now, define the Room database class that extends RoomDatabase. This class should be abstract and annotated with @Database:

@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,
                    "app_database"
                ).build()
                INSTANCE = instance
                instance
            }
        }
    }
}

In this example, the AppDatabase class includes a method to get an instance of the database, ensuring that only one instance of the database is created (singleton pattern). The userDao() abstract method provides access to the UserDao.

Step 5: Accessing the Database

With your database set up, you can now access it from your application code. Typically, you would access the database instance from a repository class. Here’s a simple example of how you might implement such a repository:

class UserRepository(private val userDao: UserDao) {

    val allUsers: LiveData> = userDao.getAllUsers()

    suspend fun insert(user: User) {
        userDao.insert(user)
    }

    suspend fun update(user: User) {
        userDao.update(user)
    }

    suspend fun delete(user: User) {
        userDao.delete(user)
    }

    suspend fun getUserById(userId: Int): User? {
        return userDao.getUserById(userId)
    }
}

The UserRepository class provides a clean API for data access to the rest of the application. It abstracts the data source from the rest of the app, making it easier to manage changes to the data source.

Step 6: Using Room with ViewModel and LiveData

To integrate Room with a ViewModel, you can use LiveData to observe data changes. Here’s an example of how you might set up a UserViewModel:

class UserViewModel(application: Application) : AndroidViewModel(application) {

    private val repository: UserRepository
    val allUsers: LiveData>

    init {
        val userDao = AppDatabase.getDatabase(application).userDao()
        repository = UserRepository(userDao)
        allUsers = repository.allUsers
    }

    fun insert(user: User) = viewModelScope.launch {
        repository.insert(user)
    }

    fun update(user: User) = viewModelScope.launch {
        repository.update(user)
    }

    fun delete(user: User) = viewModelScope.launch {
        repository.delete(user)
    }
}

In this UserViewModel, the LiveData object allUsers is observed by the UI for any changes in the data. The ViewModel uses Kotlin coroutines to perform database operations asynchronously, ensuring that these operations do not block the UI thread.

Conclusion

Room provides a powerful and efficient way to manage databases in Android applications. By following the steps outlined in this guide, you can set up Room in your project and take advantage of its features, such as compile-time query verification, LiveData support, and seamless integration with Kotlin coroutines. Implementing Room not only simplifies your database interactions but also makes your application more robust and maintainable.

With Room, you can focus more on building the core features of your app while relying on a reliable and efficient database management system to handle data persistence.

Now answer the exercise about the content:

What is the primary purpose of the Room Persistence Library in Android development?

You are right! Congratulations, now go to the next page

You missed! Try again.

Article image Using Room for Database Management: Defining Entities in Room

Next page of the Free Ebook:

80Using Room for Database Management: Defining Entities in Room

8 minutes

Obtenez votre certificat pour ce cours gratuitement ! en téléchargeant lapplication Cursa et en lisant lebook qui sy trouve. Disponible sur Google Play ou App Store !

Get it on Google Play Get it on App Store

+ 6.5 million
students

Free and Valid
Certificate with QR Code

48 thousand free
exercises

4.8/5 rating in
app stores

Free courses in
video, audio and text