Я пытаюсь протестировать свою базу данных комнаты и наблюдаю за испускаемыми LiveData, используя эту функцию, как рекомендовано в образце компонентов архитектуры приложения GitHub.
Примечание. Я получаю реляционный класс, а не стандартный Entity из таблицы. Объект отношения один-один. Хотя этот вызов работает при запуске приложения на устройстве.
Я знаю, что упускаю здесь какую-то глупую деталь. Было бы здорово, если бы вы могли указать мне на это.
fun <T> LiveData<T>.getOrAwaitValue(
time: Long = 2,
timeUnit: TimeUnit = TimeUnit.SECONDS
// afterObserve: () -> Unit = {}
): T {
var data: T? = null
val latch = CountDownLatch(1)
val observer = object : Observer<T> {
override fun onChanged(o: T?) {
data = o
latch.countDown()
this@getOrAwaitValue.removeObserver(this)
}
}
this.observeForever(observer)
// afterObserve.invoke()
// Don't wait indefinitely if the LiveData is not set.
if (!latch.await(time, timeUnit)) {
this.removeObserver(observer)
throw TimeoutException("LiveData value was never set.")
}
@Suppress("UNCHECKED_CAST")
return data as T
}
Но я получаю сообщение об ошибке, что я не могу получить доступ к данным в фоновом потоке. Я могу решить эту проблему, запустив его в основном потоке с помощью сопрограмм, но LiveData не возвращает значение и остается нулевым, что вызывает исключение TimeOutException.
Это мой тестовый метод
@Test
// @Throws(Exception::class)
fun writeBagAndItemAssociation() = runBlocking {
var bag1 = BagItem(bagId = 1, bagName = "AT", bagColor = 0)
var bag2 = BagItem(bagId = 2, bagName = "Kamiliant", bagColor = 0)
bagItemDao.insert(bag1)
bagItemDao.insert(bag2)
bag1 = bagItemDao.findItemsByName(bag1.bagName)[0]
bag2 = bagItemDao.findItemsByName(bag2.bagName)[0]
var item = InventoryItem(itemId = 1, itemName = "Blazer", bagOwnerId = bag2.bagId)
inventoryItemDao.insert(item)
CoroutineScope(Dispatchers.Main).launch {
item = inventoryItemDao.findItemsByName("Blazer").getOrAwaitValue()[0]
assertNotNull(item)
}
val itemsInBag2 =
bagItemDao.getItemsAndBagsInBagWithId(id = bag2.bagId)
assertEquals(1, itemsInBag2?.items?.size)
val itemsInBag1 =
bagItemDao.getItemsAndBagsInBagWithId(id = bag1.bagId)
assertEquals(0, itemsInBag1?.items?.size)
// val allItemsWithBag =
// inventoryItemDao.getItemsWithBag().getOrAwaitValue()
// assertThat(allItemsWithBag.size, `is`(1))
// assertEquals(1, allItemsWithBag.size)
}
ItemInventoryDao.kt
@Dao
interface InventoryItemDao : BaseDao<InventoryItem> {
/**
* Selects and returns the row that matches the supplied start time, which is our key.
*
* @param key startTimeMilli to match
*/
@Query("SELECT * from my_inventory_table WHERE itemId = :key")
fun get(key: Long): InventoryItem?
/**
* Deletes all values from the table.
*
* This does not delete the table, only its contents.
*/
@Query("DELETE FROM my_inventory_table")
fun clear()
@Query("DELETE FROM my_inventory_table WHERE itemId =:itemId")
fun delete(itemId: Long)
// @Transaction
@Query("SELECT * FROM my_inventory_table")
fun getItemsWithBag(): LiveData<List<ItemWithBag>>
@Entity
data class ItemWithBag(
@Embedded val item: InventoryItem,
@Relation(
parentColumn = "bagOwnerId",
entityColumn = "bagId"
)
val bag: BagItem
)
}