我已将示例程序从 Java/SQLite 转换为 Kotlin/Room。

我正在努力在后台线程中实现带有返回值的查询。

这已被问到,但我无法让它工作。
我已经阅读了类似问题的答案,但有些问题已被弃用,或者有些解决方案对于本应微不足道的事情来说似乎很复杂。

当我需要使用查询的返回值时,我真的很难想出一个简单的解决方案。

(如果我强制在主线程中使用 allowMainThreadQueries() 进行查询,一切都会正常工作)

这是我希望在后台线程中进行查询的功能之一:

fun getCrimes(): List<Crime> {
    val crimes = crimesDAO.getAllCrimes() as ArrayList<Crime>
    return crimes
}

我可以像下面这样调用函数并且它可以工作,但这意味着我需要在其他类中添加异步调用,它看起来并不优雅:
AsyncTask.execute {
    mCrimes = getCrimes() as ArrayList<Crime>
}

==> 我想修改 getCrimes 本身,让它在后台运行查询,例如:(以下代码不正确)
fun getCrimes(): List<Crime> {
    var crimes: ArrayList<Crime>

    AsyncTask.execute {
        crimes = crimesDAO.getAllCrimes() as ArrayList<Crime>
    }

    return crimes // This is wrong as crimes in not initialized
}

我研究了 kotlin 协程、实时数据和 rxjava,但找不到解决这个问题的简单方法。

背景资料:

这是数据类:
@Entity(tableName = "crimes_table")
class Crime {

    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name="id")
    var id: Long = 0

    @ColumnInfo(name="uuid")
    @TypeConverters(UUIDConverter::class)
    var mId: UUID = UUID.randomUUID()

    @ColumnInfo(name="title")
    var mTitle: String? = null

    @ColumnInfo(name="date")
    @TypeConverters(DateConverter::class)
    var mDate: Date? = Date()

    @ColumnInfo(name="solved")
    var mSolved: Boolean = false
}

这是 DAO:
@Dao
interface CrimesListDAO {

    @Query("SELECT * FROM crimes_table")
    fun getAllCrimes(): List<Crime>

    @Query("SELECT * FROM crimes_table WHERE uuid = :uuidString LIMIT 1")
    fun getOneCrime(uuidString: String): Crime

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertCrime(crime: Crime)

    @Update(onConflict = OnConflictStrategy.REPLACE)
    fun updateCrime(crime: Crime)

    @Delete
    fun deleteCrime(crime: Crime)
}

这是 DatabaseApp 类:
@Database(entities = [(Crime::class)], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun crimesListDAO(): CrimesListDAO
}

这是我实例化数据库的方式:
class ApplicationContextProvider : Application() {
    ...
    companion object {
        var database: AppDatabase? = null
    ...
    }

    override fun onCreate() {
        super.onCreate()
        ApplicationContextProvider.database = Room.databaseBuilder(this, AppDatabase::class.java, "crimeBase.db").build()
    }
}

最佳答案

步骤1

开启你的阻塞功能

fun getCrimes() = crimesDAO.getAllCrimes() as List<Crime>

进入暂停状态:
suspend fun getCrimes() = withContext(Dispatchers.IO) {
    crimesDAO.getAllCrimes() as List<Crime>
}

第二步

为了调用一个可挂起的函数,你必须首先启动一个协程:
override fun onSomeEvent() {
    (context as CoroutineScope).launch {
        val crimes = getCrimes()
        // work with crimes
    }
}

要了解如何使您的 context 成为 CoroutineScope ,请参阅 documentation on CoroutineScope

10-07 19:47
查看更多