User Tools

Site Tools


persist_data_with_room

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
persist_data_with_room [2026/04/01 11:39] – [5. Create an item Entity] kalaschnikowpersist_data_with_room [2026/04/01 15:31] (current) – [Persist Data with Room] kalaschnikow
Line 1: Line 1:
 +====== Persist Data with Room ======
 +
 +https://developer.android.com/codelabs/basic-android-kotlin-compose-persisting-data-room
 +
 +Gitlab repo: https://github.com/google-developer-training/basic-android-kotlin-compose-training-inventory-app/tree/main
 +===== 1. Before you begin =====
 +
 +[[Room]] is a persistence library that's part of Android Jetpack. Room is an abstraction layer on top of a SQLite database. SQLite uses a specialized language (SQL) to perform database operations. Instead of using SQLite directly, Room simplifies the chores of database setup, configuration, and interactions with the app. Room also provides compile-time checks of SQLite statements.
 +
 +...
 +===== 2. App overview =====
 +
 +...
 +===== 3. Starter app overview =====
 +
 +You can browse the code in the [[https://github.com/google-developer-training/basic-android-kotlin-compose-training-inventory-app/tree/starter|Inventory app]] GitHub repository.
 +
 +  * ui/home/HomeScreen.kt
 +    * list of items
 +  * ui/item/ItemEntryScreen.kt
 +    * item details
 +  * ui/navigation/InventoryNavGraph.kt
 +    * navigation graph for the entire application
 +===== 4. Main components of Room =====
 +  * Room entities represent tables in your app's database. You use them to update the data stored in rows in tables and to create new rows for insertion.
 +  * Room DAOs provide methods that your app uses to retrieve, update, insert, and delete data in the database.
 +  * Room Database class is the database class that provides your app with instances of the DAOs associated with that database.
 +===== 5. Create an item Entity =====
 +
 +  * An Entity class defines a table, and each instance of this class represents a row in the database table.
 +  * The ''@Entity'' annotation marks a class as a database Entity class.
 +  * Each field of the Entity is represented as a column in the database, unless denoted otherwise.
 +
 +  * Data classes are primarily used to hold data in Kotlin. They are defined with the keyword ''data''.
 +  * The ''@Entity'' annotation has several possible arguments. By default (no arguments to ''@Entity''), the table name is the same as the class name. Use the ''tableName'' argument to customize the table name.
 +
 +  * Annotate the id property with ''@PrimaryKey'' to make the id the primary key.
 +  * If you want to auto generate values  set a default value of ''0'', which is necessary to auto generate values.
 +  * Add the ''autoGenerate'' parameter to the ''@PrimaryKey'' annotation to specify whether the primary key column should be auto-generated. If ''autoGenerate'' is set to ''true'', Room will automatically generate a unique value for the primary key column when a new entity instance is inserted into the database.
 +===== 6. Create the item DAO =====
 +  * The Data Access Object (DAO) is a pattern you can use to separate the persistence layer from the rest of the application by providing an abstract interface. This isolation follows the single-responsibility principle, which you have seen in previous codelabs.
 +  * The DAO you create is a custom interface that provides convenience methods for querying/retrieving, inserting, deleting, and updating the database. Room generates an implementation of this class at compile time. The Room library provides convenience annotations, for defining methods that perform SQL statements, e.g.:
 +    * ''@Insert''
 +    * ''@Delete'' 
 +    * ''@Update''
 +    * ''@Query''
 +    * ...?
 +  
 +  * The argument ''onConflict'' tells the Room what to do in case of a conflict. The ''OnConflictStrategy.IGNORE'' strategy ignores a new item.
 +
 +  * It is recommended to use ''Flow'' in the persistence layer. With ''Flow'' as the return type, you receive notification whenever the data in the database changes. The Room keeps this ''Flow'' updated for you, which means you only need to explicitly get the data once.
 +  * Because of the ''Flow'' return type, Room also runs the query on the background thread. You don't need to explicitly make it a ''suspend'' function and call it inside a coroutine scope.
 +===== 7. Create a Database instance =====
 +
 +  * The Database class provides your app with instances of the DAOs you define.
 +  * You need to create an abstract ''RoomDatabase'' class and annotate it with ''@Database''. This class has one method that returns the existing instance of the ''RoomDatabase'' if the database doesn't exist.
 +
 +  * Create a ''public abstract class'' that extends ''RoomDatabase''. The new abstract class you define acts as a database holder. The class you define is abstract because Room creates the implementation for you.
 +  * Annotate the class with ''@Database''. In the arguments, list the entities for the database and set the version number. The ''@Database'' annotation requires several arguments so that Room can build the database.
 +    * Specify the list of entities.
 +    * Set the version. Whenever you change the schema of the database table, you have to increase the version number.
 +    * Set ''exportSchema'' to false so as not to keep schema version history backups.
 +  * define a ''companion object'', which allows access to the methods to create or get the database and uses the class name as the qualifier.
 +  * Inside the ''companion object'', declare a private nullable variable ''Instance'' for the database and initialize it to null.
 +  * Annotate ''Instance'' with ''@Volatile''. 
 +    * The value of a volatile variable is never cached, and all reads and writes are to and from the main memory. These features help ensure the value of Instance is always up to date and is the same for all execution threads. It means that changes made by one thread to Instance are immediately visible to all other threads.
 +  * Below ''Instance'', while still inside the companion object, define a ''getDatabase()'' method with a ''Context'' parameter that the database builder needs.
 +  * ...
 +
 +
 +"Template code" for future projects:
 +
 +<code kotlin>
 +import android.content.Context
 +import androidx.room.Database
 +import androidx.room.Room
 +import androidx.room.RoomDatabase
 +
 +/**
 +* Database class with a singleton Instance object.
 +*/
 +@Database(entities = [Item::class], version = 1, exportSchema = false)
 +abstract class InventoryDatabase : RoomDatabase() {
 +
 +    abstract fun itemDao(): ItemDao
 +
 +    companion object {
 +        @Volatile
 +        private var Instance: InventoryDatabase? = null
 +
 +        fun getDatabase(context: Context): InventoryDatabase {
 +            // if the Instance is not null, return it, otherwise create a new database instance.
 +            return Instance ?: synchronized(this) {
 +                Room.databaseBuilder(context, InventoryDatabase::class.java, "item_database")
 +                    .build()
 +                    .also { Instance = it }
 +            }
 +        }
 +    }
 +}
 +
 +</code> 
 +
 +===== 8. Implement the Repository =====
 +
 +...
 +
 +
 +===== 9. Add the save functionality =====
 +
 +...
 +===== View the database content using Database Inspector =====
 +
 +===== Get the solution code =====
 +
 +===== Summary =====
 +
 +===== Learn more =====