Правильный сбор потока из помещения

Я перенес свое приложение с простого SQLite на использование Room, чтобы сделать его более надежным. Теперь у меня есть поток, который запрашивает всех моих пользователей из базы данных внутри моего DAO:

@Query("SELECT * FROM users")
fun getAllAsFlow(): Flow<List<UserData>>

В моем репозитории я представляю это как:

val allUsersFlow: Flow<List<UserData>> = userDao.getAllAsFlow()

И затем в моей ViewModel:

val allUsers: Flow<List<UserData>> = repository.allUsersFlow

Чтобы наконец собрать его в Composable с Lifecyleawareness

 val users by usersPageViewModel.allUsers.collectAsStateWithLifecycle(initialValue = listOf())

Теперь все работает так, как ожидалось, но когда я перехожу на другую страницу (с помощью push to stack), а затем снова извлекаю ее, Composable перекомпоновывается, и пользователи представляют собой пустой список, прежде чем он снова получит данные, что приводит к пустому экрану. просмотр на долю секунды.

Теперь, если я заменю collectAsStateWithLifecycle на collectAsState, этого не произойдет, потому что коллекция не знает, что первый экран переходит на задний план.

Итак, каков наилучший способ добиться поведения collectAsState, но при этом учитывать глобальный жизненный цикл приложения (например, переход в фоновый режим)? Могу ли я как-то передать collectAsStateWithLifecycle жизненный цикл основных действий?

3
0
96
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В вашей модели представления вам просто нужно преобразовать холодный поток из репозитория в горячий StateFlow:

val allUsers: StateFlow<List<UserData>> = repository.allUsersFlow.stateIn(
    scope = viewModelScope,
    started = SharingStarted.WhileSubscribed(5_000),
    initialValue = emptyList(),
)

Таким образом, ваша модель представления всегда имеет значение для потока и может предоставить его при необходимости.

Поскольку теперь вы предоставляете initialValue в модели представления, вы можете удалить его из collectAsStateWithLifecycle в своей компонуемой модели.

ах, спасибо, это похоже на тот шаг, который я пропустил. Тайм-аут WhileSubscribed предназначен для вращений и прочего, когда модель представления приостановлена, верно? эти потоки могут сбить с толку :)

Tom 18.04.2024 09:14

Это верно. Когда компонуемый объект, собирающий поток, покидает композицию (например, при реконфигурации устройства, например при ротации), подписка на поток отменяется. StateFlow тогда также остановит восходящие потоки. Когда ваш компонуемый объект немедленно переподписывается из-за ротации устройства, потоки необходимо запустить заново. Чтобы упростить это, StateFlow ждет 5 секунд после ухода последнего подписчика, прежде чем останавливать восходящие потоки, поэтому любые повторные подписки в течение этого времени не прерывают восходящие потоки.

Leviathan 18.04.2024 11:01

Другие вопросы по теме