我已将示例程序从 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
。