[英]Room Database Returns Null Using Coroutine Async
我目前正在嘗試在不使用 ViewModel 的情況下從我的房間數據庫中獲取數據。 這是因為我正在開發一個 NotificationHandler,它可以在任何時候由警報管理器觸發。
以下是我到目前為止的代碼。 下面的代碼從另一個 class 調用sortNotification
開始。 sortNotification
然后調用launchAsyncTask
,后者又通過調用getQuotesFromDatabase
進入數據庫。 然后我等待結果(我相信),將數據庫中的數據分配給listOfQuotes
變量,然后調用displayNotification
來使用它。 我的問題是,當我嘗試使用它時, listOfQuotes
總是 null displayNotification
。
現在我知道數據庫有內容,當我打開我的應用程序和 go 到具有 ViewModel 的 Activity 時,數據已成功檢索。 我認為我的問題可能與異步任務未正確完成或我的 coroutineScope 有關。 當代碼進入displayNotification
時,我只需要listOfQuotes
來獲取數據。 任何幫助將不勝感激。 提前致謝。
private var job = Job()
private val ioScope = CoroutineScope(Dispatchers.IO + job)
private lateinit var listOfQuotes: LiveData<List<DefaultQuote>>
fun sortNotification() {
launchAsyncTask()
}
private fun launchAsyncTask() = CoroutineScope(Dispatchers.IO).launch {
val asyncTask = ioScope.async {
getQuotesFromDatabase()
}
listOfQuotes = asyncTask.await()
displayNotification()
}
private suspend fun getQuotesFromDatabase(): LiveData<List<DefaultQuote>> {
return withContext(Dispatchers.IO) {
val defaultQuoteDao = QuoteDatabase.getDatabase(context, this).defaultQuoteDao()
val defaultQuoteRepository = DefaultQuoteRepository(defaultQuoteDao)
defaultQuoteRepository.allQuotes
}
}
private fun displayNotification() {
val quote = listOfQuotes.value?.let {
val size = it.size
val randomIndex = (0..size).random()
it[randomIndex]
} ?: throw NullPointerException("Quotes not found")
// ... then do notification stuff
我還從我的 DAO 中添加了代碼:
@Dao
interface DefaultQuoteDao {
@Query("SELECT * FROM $DEFAULT_TABLE_NAME")
fun getAllQuotes(): LiveData<List<DefaultQuote>>
}
以及我的存儲庫中的代碼:
class DefaultQuoteRepository(private val defaultQuoteDao: DefaultQuoteDao) {
val allQuotes: LiveData<List<DefaultQuote>> = defaultQuoteDao.getAllQuotes()
}
以及QuoteDatabase.getDatabase(Context, CoroutineScope)
的代碼:
fun getDatabase(context: Context, scope: CoroutineScope): QuoteDatabase {
val tempInstance = INSTANCE
if (tempInstance != null) {
return tempInstance
}
synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
QuoteDatabase::class.java,
DATABASE_NAME
)
.fallbackToDestructiveMigration()
.addCallback(QuoteDatabaseCallback(scope))
.build()
INSTANCE = instance
return instance
}
}
具體問題是您永遠不會觀察listOfQuotes
LiveData 的值。 這是啟動從數據庫中提取所必需的。
總的來說,你正在以一種奇怪的方式做到這一點。 您應該使用協程或 LiveData。 它們都允許您觀察數據庫中的數據,但您不需要兩者。 這就像在內部包裝異步調用和異步調用,然后必須將它們都解開。 您應該:
getAllQuotes
返回Flow<List<DefaultQuote>>
我建議 2. 如果您希望您的應用程序變得中型或復雜。 Flow
允許您以更簡潔靈活的方式map或組合數據。
然后,您的 function sortNotification
將變為:
// Ideally this should be injected into the class, but for a Service that's a little difficult.
// At a minimum you should initialize it once for the class
val defaultQuoteRepository: DefaultQuoteRepository by lazy {
DefaultQuoteRepository(QuoteDatabase.getDatabase(context, this).defaultQuoteDao())
}
fun sortNotification() {
defaultQuoteRepository.allQuotes
.map { listOfQuotes ->
listOfQuotes.random()
}
.flowOn(Dispatchers.IO)
.onEach { randomQuote ->
displayNotification(randomQuote)
}
// This makes the above onEach lambda run on the main thread so you're safe to show notifications.
// Ideally you should have a specific scope defined but tbh if you're not testing it's not that important
.launchIn(GlobalScope)
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.