简体   繁体   中英

Room Dao LiveData as return type causing compile time error

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

implementation "androidx.room:room-runtime:2.1.0-alpha04"
kapt "androidx.room:room-compiler:2.1.0-alpha04"

But when I added new Room coroutine dependency as mentioned below.

implementation "androidx.room:room-runtime:2.1.0-alpha04"
implementation "androidx.room:room-coroutines:2.1.0-alpha04"
kapt "androidx.room:room-compiler:2.1.0-alpha04"

Below is code which compiles

@Dao
interface AccountDao{

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

Below is the code which gives error.

@Dao
interface AccountDao{

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

started to receive error.

PlayGround/app/build/tmp/kapt3/stubs/debug/com/playground/www/x/datasource/dao/AccountDao.java:11: error: Not sure how to convert a Cursor to this method's return type (androidx.lifecycle.LiveData<java.util.List<com.playground.www.x.datasource.entity.Account>>).
public abstract java.lang.Object getAllAccounts(@org.jetbrains.annotations.NotNull()

Any one facing similar issue?

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)
    }
}

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'

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>>
}

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.

Not same, but similar. RoomWordSample CodeLab worked fine until I updated Android Studio and then Gradle plugins.

The failing code is below from the WordDao class. Flow was not recognized.

@Query("SELECT * FROM word_table ORDER BY word ASC")
fun getAlphabetizedWords(): Flow<List<Word>>

I had used the following import, which worked before, but was failing after the updates.

import kotlinx.util.concurrent.Flow

I had to change the import statement as follows:

import kotlinx.coroutines.flow.Flow

I also made quite a few dependency changes too, but Coroutine change was likely needed for this fix.

ext {
    activityVersion = '1.4.0'
    appCompatVersion = '1.4.0'
    lifecycleVersion = '2.4.0'
    coroutines = '1.5.2'
    roomVersion = '2.3.0'
}

dependencies {

implementation "androidx.appcompat:appcompat:$rootProject.appCompatVersion"
implementation "androidx.activity:activity-ktx:$activityVersion"

// Dependencies for working with Architecture components
// You'll probably have to update the version numbers in build.gradle (Project)

// Room components
implementation "androidx.room:room-ktx:$rootProject.roomVersion"
kapt "androidx.room:room-compiler:$rootProject.roomVersion"
androidTestImplementation "androidx.room:room-testing:$rootProject.roomVersion"

implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.0'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.2'
implementation 'androidx.room:room-common:2.3.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2'
implementation 'androidx.room:room-ktx:2.3.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'

// Lifecycle components
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$rootProject.lifecycleVersion"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$rootProject.lifecycleVersion"
implementation "androidx.lifecycle:lifecycle-common-java8:$rootProject.lifecycleVersion"

// Kotlin components
//implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.6.0'
api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$rootProject.coroutines"
api "org.jetbrains.kotlinx:kotlinx-coroutines-android:$rootProject.coroutines"

}

Another failure was due to missing @Dao annotation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM