Android Room Kotlin - 在后台线程中查询 - 返回值问题

Wil*_*ill 4 android kotlin rx-java android-room kotlin-coroutines

我已经将一个示例程序从Java/SQLite转换为Kotlin/Room.

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

有人问过,但是我无法让它发挥作用.我已经阅读了类似问题的答案,但有些已被弃用,或者某些解决方案似乎很复杂,应该是微不足道的.

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

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

这是我想在后台线程中进行查询的函数之一:

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

我可以调用函数如下,它可以工作,但这意味着我需要在其他类中添加异步调用,它看起来不优雅:

AsyncTask.execute {
    mCrimes = getCrimes() as ArrayList<Crime>
}
Run Code Online (Sandbox Code Playgroud)

==>我想修改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
}
Run Code Online (Sandbox Code Playgroud)

我查看了kotlin coroutines,Live Data和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
}
Run Code Online (Sandbox Code Playgroud)

这是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)
}
Run Code Online (Sandbox Code Playgroud)

这是DatabaseApp类:

@Database(entities = [(Crime::class)], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun crimesListDAO(): CrimesListDAO
}
Run Code Online (Sandbox Code Playgroud)

这是我实例化数据库的方式:

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

Mar*_*nik 8

第一步

转动你的阻止功能

fun getCrimes() = crimesDAO.getAllCrimes() as List<Crime>
Run Code Online (Sandbox Code Playgroud)

进入暂停状态:

suspend fun getCrimes() = withContext(Dispatchers.IO) { 
    crimesDAO.getAllCrimes() as List<Crime>
}
Run Code Online (Sandbox Code Playgroud)

第二步

要调用可挂起的函数,必须首先启动一个协程:

override fun onSomeEvent() {
    (context as CoroutineScope).launch {
        val crimes = getCrimes()
        // work with crimes
    }
}
Run Code Online (Sandbox Code Playgroud)

要了解如何使您context成为a CoroutineScope,请参阅上的文档CoroutineScope.


luc*_*ino 0

默认情况下,使用 Room 对数据库的所有请求都必须在后台线程中进行。为什么不使用协程?你可以将它与这样的东西一起使用:

suspend fun retrieveCrimes(): List<Crime> {
    return async {
        delay(5000)
        1
    }.await()
}
Run Code Online (Sandbox Code Playgroud)