Room Dao LiveData作为返回类型导致编译时间错误

时间:2019-02-07 05:10:28

标签: android android-room android-architecture-components kotlin-coroutines

我正在使用房间,并实现了返回<LiveData Dao 。添加以下依赖项后,它运行良好。

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

但是当我添加如下所述的新的Room coroutine依赖项时。

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"

下面是编译的代码

@Dao
interface AccountDao{

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

下面是给出错误的代码。

@Dao
interface AccountDao{

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

开始收到错误消息。

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

有人面临类似的问题吗?

4 个答案:

答案 0 :(得分:4)

删除暂停功能。 LiveData已经是异步的。不需要暂停功能。

@Dao
interface AccountDao{

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

答案 1 :(得分:2)

房间的当前实现不支持与LiveData一起使用的协程。作为一种解决方法,您可以像下面这样实现它:

@Dao
interface AccountDao{

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

在实现ViewModel类的过程中,您可以创建LiveData并为其分配一个值,该值是从数据库中检索的:

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

要使用Dispatchers.Main导入:

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1'

答案 2 :(得分:1)

正如Michael Vescovo所指出的,实现异步调用有两种可能的方法:

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

您将使用哪种取决于您的用例。例如,如果我的DAO使用者(通常是存储库)将为模型创建LiveData(在我不需要观察本地数据库的更改的情况下),我将使用第一个。

如果我需要观察本地数据库中的更改(例如,与此同时某些其他服务可以更新数据库),我将使用第二个。

答案 3 :(得分:0)

我认为这里的解决方案实际上是不使用协程而返回LiveData 。 LiveData开箱即用,返回LiveData时无需使用协程。

使用LiveData时,它已经在后台线程上对其进行了处理。如果不使用LiveData,则在这种情况下,您可以使用协程(可能最终会成为协程通道)或RxJava2。

有关示例,请参见此代码实验室:https://codelabs.developers.google.com/codelabs/android-room-with-a-view-kotlin。在这里,他们需要一个后台线程进行插入,而不需要返回的LiveData。

注意:在实际的代码实验室中,DAO没有返回LiveData似乎是一个错误。我已在下面的示例中对此进行了纠正。

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