Room Dao LiveData as return type causing compile time error

后端 未结 4 1754
感情败类
感情败类 2020-12-06 01:12

I am using Room and implemented Dao that returns LiveData. It was working fine with below dependency added.

im         


        
相关标签:
4条回答
  • 2020-12-06 01:32

    Remove the suspend function. LiveData is already asynchronous. No need for a suspend function.

    @Dao
    interface AccountDao{
    
        @Query("SELECT * FROM account_master")
        fun getAllAccounts(): LiveData<List<Account>>
    }
    
    0 讨论(0)
  • 2020-12-06 01:37

    I think the solution here is actually to just return the LiveData without using Coroutines. LiveData works out of the box, there's no reason to use Coroutines when returning LiveData.

    When using LiveData it already handles it on a background thread. When NOT using LiveData then in that case you can use Coroutines (and maybe eventually Coroutines Channels) or RxJava2.

    See this codelab for an example: https://codelabs.developers.google.com/codelabs/android-room-with-a-view-kotlin. Here they need a background thread for inserts but not for the returned LiveData.

    Note: there seems to be a mistake in the actual codelab where the DAO is not returning a LiveData. I've corrected that in the sample below.

    @Dao
    interface WordDao {
    
        @Query("SELECT * from word_table ORDER BY word ASC")
        fun getAllWords(): LiveData<List<Word>>
    
        @Insert
        suspend fun insert(word: Word)
    
        @Query("DELETE FROM word_table")
        fun deleteAll()
    }
    
    class WordRepository(private val wordDao: WordDao) {
    
        val allWords: LiveData<List<Word>> = wordDao.getAllWords()
    
        @WorkerThread
        suspend fun insert(word: Word) {
            wordDao.insert(word)
        }
    }
    
    0 讨论(0)
  • 2020-12-06 01:39

    As Michael Vescovo pointed out, there are two possible ways of achieving async call:

    @Dao
    interface AccountDao{
        @Query("SELECT * FROM account_master")
        suspend fun getAllAccounts(): List<Account>
    }
    
    @Dao
    interface AccountDao{
        @Query("SELECT * FROM account_master")
        fun getAllAccounts(): LiveData<List<Account>>
    }
    

    Which one you'll use depends on your use case. For example, I would use the first one if my DAO consumer (usually repository) will create LiveData for the model (in the case that I don't need to observe changes from local DB).

    If I need to observe changes in local DB (for example, some other service can update DB in the meantime) I would use the second one.

    0 讨论(0)
  • 2020-12-06 01:43

    Current implementation of Room doesn't support coroutines with LiveData. As a workaround you can implement it like the following:

    @Dao
    interface AccountDao{
    
    @Query("SELECT * FROM account_master")
        suspend fun getAllAccounts(): List<Account>
    }
    

    And in your implementation of ViewModel class you can create LiveData and assign a value to it, retrieved from DB:

    class MainViewModel : ViewModel() {
        private val dao: AccountDao = ...// initialize it somehow
        private var job: Job = Job()
        private val scope = CoroutineScope(job + Dispatchers.Main)
        lateinit var accounts: MutableLiveData<List<Account>>
    
        override fun onCleared() {
            super.onCleared()
            job.cancel()
        }
    
        fun getAccounts(): LiveData<List<Account>> {
            if (!::accounts.isInitialized) {
                accounts = MutableLiveData()
    
                scope.launch {
                    accounts.postValue(dao.getAllAccounts())
                }
    
            }
            return accounts
        }
    }
    

    To use Dispatchers.Main import:

    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1'
    
    0 讨论(0)
提交回复
热议问题