Ask Your Question
3

How to appropriately utilize Android Room with Kotlin Coroutines?

asked 2023-05-13 08:22:11 +0000

nofretete gravatar image

edit retag flag offensive close merge delete

1 Answer

Sort by ยป oldest newest most voted
2

answered 2023-05-13 08:48:02 +0000

scrum gravatar image
  1. Import Room Library:

    implementation "androidx.room:room-runtime:2.3.0"
    implementation "androidx.room:room-ktx:2.3.0"
    
  2. Define the entities:

    @Entity(tableName = "account_tb")
    data class AccountEntity(
        @PrimaryKey val id: String,
        val name: String
    )
    
  3. Define the DAO:

    @Dao
    interface AccountDao {
    
       @Query("SELECT * FROM account_tb")
       suspend fun getAccounts(): List<AccountEntity>
    
       @Insert(onConflict = OnConflictStrategy.REPLACE)
       suspend fun saveAccounts(account: List<AccountEntity>)
    
       @Query("DELETE FROM account_tb")
       suspend fun deleteAccounts()
    }
    
  4. Define the Room database:

    @Database(entities = [AccountEntity::class], version = 1, exportSchema = false)
    abstract class AppDatabase : RoomDatabase() {
    
        abstract fun accountDao(): AccountDao
    
        companion object {
            @Volatile
            private var instance: AppDatabase? = null
    
            fun getInstance(context: Context): AppDatabase {
                return instance ?: synchronized(this) {
                    Room.databaseBuilder(
                        context.applicationContext,
                        AppDatabase::class.java,
                        "app_db"
                    ).build().also { instance = it }
                }
            }
        }
    }
    

    Note: Here, we have created an AppDatabase class that extends RoomDatabase. It has an abstract function named accountDao() that returns the AccountDao. The companion object is used to implement the Singleton pattern to have only one instance of the database during the whole app lifecycle.

  5. Utilize Coroutines to access data from the database:

    class AccountRepository(private val appDatabase: AppDatabase) {
    
       suspend fun getAccounts(): List<AccountEntity> = withContext(Dispatchers.IO) {
           appDatabase.accountDao().getAccounts()
       }
    
       suspend fun saveAccounts(accounts: List<AccountEntity>) = withContext(Dispatchers.IO) {
           appDatabase.accountDao().saveAccounts(accounts)
       }
    
       suspend fun deleteAccounts() = withContext(Dispatchers.IO) {
           appDatabase.accountDao().deleteAccounts()
       }
    }
    

    Note: Here, we have created a repository class to provide a layer of abstraction for the database operation. In the getAccounts() method, we utilize the withContext() function to switch to the IO thread and execute the database query. Similarly, we utilize the same withContext() function to execute the database operations in the saveAccounts() and deleteAccounts() methods.

  6. Use ViewModel to handle data updates:

    class AccountViewModel(private val accountRepository: AccountRepository) : ViewModel() {
    
       private val _accounts = MutableLiveData<List<AccountEntity>>()
       val accounts: LiveData<List<AccountEntity>> = _accounts
    
       fun getAccounts() {
           viewModelScope.launch {
               _accounts.postValue(accountRepository.getAccounts())
           }
       }
    
       fun saveAccounts(accounts: List<AccountEntity>) {
           viewModelScope.launch {
               accountRepository.saveAccounts(accounts)
           }
       }
    }
    

    Note: Here, we create a ViewModel class called AccountViewModel to provide data to the UI. In the class, we declare variables that represent the data (in this case, the list of accounts) as LiveData variables. We also create methods that utilize coroutines to retrieve or update data from the database. We utilize the viewModelScope.launch{} function to control the lifecycle of these coroutines.

  7. Observe LiveData to update the UI:

    class MainActivity : AppCompatActivity() {
    
       lateinit var accountViewModel: AccountViewModel
    
       override fun onCreate(savedInstanceState: Bundle?) {
           super.onCreate(savedInstanceState)
           setContentView(R.layout.activity_main)
    
           val appDatabase = AppDatabase.getInstance(this)
           val accountRepository = AccountRepository(appDatabase)
    
           accountViewModel = ViewModelProvider(
               this, ViewModelFactory(accountRepository)
           ).get(AccountViewModel::class.java)
    
           accountViewModel.accounts.observe(this, Observer {
               // update UI
           })
       }
    }
    

    Note: Here, we initialize the accountViewModel in the MainActivity's onCreate() function using the ViewModelProvider. We also observe the LiveData variable(accounts) to update the UI when it changes. The Observer function is called every time the LiveData is updated with a new value.

edit flag offensive delete link more

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account. This space is reserved only for answers. If you would like to engage in a discussion, please instead post a comment under the question or an answer that you would like to discuss

Add Answer


Question Tools

Stats

Asked: 2023-05-13 08:22:11 +0000

Seen: 15 times

Last updated: May 13 '23