Библиотека Android Room с Kotlin Flow toList () не работает
Я сделал простой пример приложения с использованием Room и Flows:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val build = Room.databaseBuilder(this, FinanceDatabase::class.java, "database.db")
.fallbackToDestructiveMigration()
.build()
GlobalScope.launch {
build.currencyDao().addCurrency(CurrencyLocalEntity(1))
val toList = build.currencyDao().getAllCurrencies().toList()
Log.d("test", "list - $toList")
}
}
}
@Entity(tableName = "currency")
data class CurrencyLocalEntity(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "currencyId")
var id: Int
) {
constructor() : this(-1)
}
@Dao
interface CurrencyDao {
@Query("SELECT * FROM currency")
fun getAllCurrencies(): Flow<CurrencyLocalEntity>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun addCurrency(currency: CurrencyLocalEntity)
}
@Database(entities = [CurrencyLocalEntity::class], version = 1)
abstract class FinanceDatabase : RoomDatabase() {
abstract fun currencyDao(): CurrencyDao
}
Я хочу использовать toList()
работает как в коде выше, но что-то идет не так, и даже журнал не печатается. В то же время используяcollect()
работает нормально и дает мне все записи.
Кто-нибудь может объяснить мне, что не так? Спасибо.
5 ответов
Здесь есть пара ошибок, но я остановлюсь на основной проблеме.
Flow
s, возвращаемые room, генерируют результат запроса каждый раз при изменении базы данных. (Это может быть ограничено изменениями таблицы, а не всей базы данных).
Поскольку база данных может измениться в любой момент в будущем, Flow
(более или менее) никогда не завершится, потому что изменение может произойти всегда.
Ваше призвание toList()
на возвращенный Flow
приостановится навсегда, так как Flow
никогда не завершается. Концептуально это имеет смысл, поскольку Room не может предоставить вам список всех изменений, которые произойдут, не дожидаясь их появления. Я уверен, ты знаешь почемуcollect
дает вам записи и toList()
нет.
Вы, вероятно, захотите вот это.
@Query("SELECT * FROM currency")
fun getAllCurrencies(): Flow<List<CurrencyLocalEntity>>
Таким образом, вы можете получить первый результат запроса с помощью Flow<...>.first()
.
Поток в комнате предназначен для наблюдения за изменениями в таблице.
Всякий раз, когда в таблицу вносятся какие-либо изменения, независимо от того, какая строка изменяется, запрос будет повторно запущен, и поток будет выдавать снова.
Однако такое поведение базы данных также означает, что, если мы обновим несвязанную строку, наш Flow будет генерировать снова с тем же результатом. Поскольку триггеры базы данных SQLite разрешают уведомления только на уровне таблицы, а не на уровне строки, Room не может знать, что именно изменилось в данных таблицы.
Убедитесь, что тот же объект doa, который вы используете для получения списка, используется для обновления базы данных. кроме этого преобразование потока в liveata выполняется с использованием функции расширения asLivedata
Для меня ниже решение работает для обновления представления с изменениями таблицы базы данных.
Решение: Тот же объект Дао следует использовать, когда мы вставляем данные в базу данных комнаты и получаем информацию из БД.
Если вы используете рукоять кинжала, то
Аннотация @Singleton будет работать.
Я надеюсь, что это решит вашу проблему.
**getAllCurrencies()** function should be suspend.
Please check the syntax to collect List from Flow:
suspend fun <T> Flow<T>.toList(
destination: MutableList<T> = ArrayList()
): List<T> (source)
https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/to-list.html