是否可以在返回 LiveData 的 Room @DAO 中编写“挂起”函数?

Ank*_*nkh 5 kotlin android-room kotlin-coroutines

我正在尝试将 @Dao 对象的所有方法转换为可挂起以供 Kotlin 协程使用。

当我将挂起修饰符添加到工作函数定义并尝试在 Android Studio 中构建时,它无法生成 XXXXDao_Impl.java 类

一个非常精简的例子:

import androidx.lifecycle.LiveData
import androidx.room.*

@Database(entities = [SomeData::class], version = 1)
abstract class SomeDatabase : RoomDatabase() {
    abstract fun getDao(): SomeDataDao
}

@Entity
data class SomeData(@PrimaryKey val id: Int, val name: String)

@Dao
interface SomeDataDao {
    @Query("SELECT * FROM SomeData") // Works
    fun getAllSync(): List<SomeData>

    @Query("SELECT * FROM SomeData") // Works
    suspend fun getAllSuspend(): List<SomeData>

    @Query("SELECT * FROM SomeData") // Works
    fun getAllSyncLiveData(): LiveData<List<SomeData>>

    @Query("SELECT * FROM SomeData") // Fails to generate code
    suspend fun getAllSuspendLiveData(): LiveData<List<SomeData>>
}
Run Code Online (Sandbox Code Playgroud)

生成的代码失败:

import androidx.lifecycle.LiveData
import androidx.room.*

@Database(entities = [SomeData::class], version = 1)
abstract class SomeDatabase : RoomDatabase() {
    abstract fun getDao(): SomeDataDao
}

@Entity
data class SomeData(@PrimaryKey val id: Int, val name: String)

@Dao
interface SomeDataDao {
    @Query("SELECT * FROM SomeData") // Works
    fun getAllSync(): List<SomeData>

    @Query("SELECT * FROM SomeData") // Works
    suspend fun getAllSuspend(): List<SomeData>

    @Query("SELECT * FROM SomeData") // Works
    fun getAllSyncLiveData(): LiveData<List<SomeData>>

    @Query("SELECT * FROM SomeData") // Fails to generate code
    suspend fun getAllSuspendLiveData(): LiveData<List<SomeData>>
}
Run Code Online (Sandbox Code Playgroud)

构建错误消息:

/Projects/Android/RawQuerySuspendTest/app/build/tmp/kapt3/stubs/debug/com/example/android/rawquerysuspendtest/SomeDataDao.java:24: error: Not sure how to convert a Cursor to this method's return type (androidx.lifecycle.LiveData<java.util.List<com.example.android.rawquerysuspendtest.SomeData>>).
    public abstract java.lang.Object getAllSuspendLiveData(@org.jetbrains.annotations.NotNull()
Run Code Online (Sandbox Code Playgroud)

应用程序的 build.gradle

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.example.android.rawquerysuspendtest"
        minSdkVersion 21
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'androidx.appcompat:appcompat:1.0.2'
    implementation 'androidx.core:core-ktx:1.0.2'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:runner:1.2.0'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

    kapt "androidx.room:room-compiler:2.1.0-rc01"
    implementation "androidx.room:room-runtime:2.1.0-rc01"
    implementation "androidx.room:room-ktx:2.1.0-rc01"

    implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.2.0-alpha01'
    implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0-alpha01'
    implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0-alpha01'
    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0-alpha01'
}
Run Code Online (Sandbox Code Playgroud)

我是否缺少依赖项或注释处理步骤?

Ser*_*gey 7

当前实施不支持协同程序LiveData。作为一种解决方法,您可以像下面这样实现它:

@Dao
interface AccountDao{

@Query("SELECT * FROM account_master")
    suspend fun getAllAccounts(): List<Account>
}
Run Code Online (Sandbox Code Playgroud)

在您的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
    }
}
Run Code Online (Sandbox Code Playgroud)

使用Dispatchers.Main导入:

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1'
Run Code Online (Sandbox Code Playgroud)

  • 使用这种方法,您将不会收到 LiveData 上的更新事件。您可以在 DAO 上使用 LiveData 并且根本不使用协程,而不是使用协程而不获取更新事件。 (4认同)