Безопасное использование Flows в Jetpack Compose
Рекомендуемый подход подписки Flows — подписка с учетом жизненного цикла. Если вы создаете приложение Android с помощью Jetpack Compose, используйте API collectAsStateWithLifecycle для сбора потоков с учетом жизненного цикла из вашего пользовательского интерфейса. CollectAsStateWithLifecycle позволяет вашему приложению сохранять ресурсы приложения, когда они не нужны, например, когда приложение находится в фоне. Ненужное сохранение ресурсов может повлиять на работоспособность устройства пользователя. К таким ресурсам могут относиться запросы Firebase, обновления местоположения или сети, а также подключения к базе данных.
В статье будет рассмотрены различия collectAsStateWithLifecycle и collectAsState.
collectAsStateWithLifecycle
collectAsStateWithLifecycle — это composable функция, которая собирает значения из Flow и представляет последнее значение State с учетом жизненного цикла. Каждый раз, когда происходит Flow.emit, значение State.value обновляется. Это вызывает рекомпозицию каждого использования State.value в Composition.
По умолчанию collectAsStateWithLifecycle использует Lifecycle.State.STARTED для запуска и остановки сбора значений из потока. Это происходит, когда Lifecycle входит и выходит из целевого состояния. Это состояние жизненного цикла можно настроить в параметре minActiveState.
collectAsStateWithLifecycle по умолчанию отменяет подписку Flow, когда приложение находится в фоновом режиме.
В следующем фрагменте показано, как использовать collectAsStateWithLifecycle для сбора поля uiState StateFlow, которое ViewModel предоставила в вашей компонуемой функции:
@Composable
fun AuthorRoute(
onBackClick: () -> Unit,
modifier: Modifier = Modifier,
viewModel: AuthorViewModel = hiltViewModel()
) {
val uiState: AuthorScreenUiState by viewModel.uiState.collectAsStateWithLifecycle()
AuthorScreen(
authorState = uiState.authorState,
newsState = uiState.newsState,
modifier = modifier,
onBackClick = onBackClick,
onFollowClick = viewModel::followAuthorToggle,
)
}
Каждый раз, когда uiState AuthorViewModel эмитит новое значение AuthorScreenUiState, AuthorRoute будет рекомпозирован.Чтобы начать использовать API collectAsStateWithLifecycle в своем проекте, добавьте артефакт androidx.lifecycle.lifecycle-runtime-compose в свой проект.
dependencies {
implementation "androidx.lifecycle:lifecycle-runtime-compose:2.6.0"
}
Под капотом
Под капотом реализация collectAsStateWithLifecycle использует API repeatOnLifecycle, который является рекомендуемым способом сбора потоков в Android с использованием системы View. collectAsStateWithLifecycle избавляет вас от необходимости вводить шаблонный код, показанный ниже, который также собирает потоки с учетом жизненного цикла из составной функции:
@Composable
fun AuthorRoute(...) {
val lifecycle = LocalLifecycleOwner.current.lifecycle
val uiState by produceState(
initialValue = viewModel.uiState.value
key1 = lifecycle
key2 = viewModel
) {
lifecycle.repeatOnLifecycle(state = STARTED) {
viewModel.uiState.collect { value = it }
}
}
AuthorScreen(...)
}
collectAsState
Можно задаться вопросом: если collectAsStateWithLifecycle — самый безопасный способ подписки на Flow из Composable функций в Android, зачем нам теперь нужен API collectAsState? или почему бы не добавить функциональность, учитывающую жизненный цикл, в collectAsState вместо создания нового API?
Жизненный цикл компонуемой функции не зависит от платформы, на которой работает Compose. Как описано в документации Lifecycle of composables page, экземпляры Compsable функций входят в композицию, рекомпозируются 0 или более раз и покидают Composition.
Жизненный цикл экземпляра Composable функции в Composition
API collectAsState следует жизненному циклу Composition. Он подписывается на Flow, когда Compsable объект входит в Composition, и прекращает сбор, когда он покидает Composition. CollectAsState — это платформенно-независимый API, который можно использовать для подписки.
Однако при использовании Compose в приложении Android жизненный цикл Android также играет важную роль в том, как следует управлять ресурсами. Даже если Compose останавливает рекомпозиции, пока приложение Android находится в фоновом режиме, collectAsState сохраняет Flow активной. Это делает невозможным освобождение ресурсов остальной частью иерархии.
Оба метода collectAsState и collectAsStateWithLifecycle имеют свое предназначение в Compose. Последний при разработке приложений Android, первый при разработке для других платформ.
Переход с collectAsState на collectAsStateWithLifecycle не вызывает никаких затруднений:
@Composable
fun AuthorRoute(
onBackClick: () -> Unit,
modifier: Modifier = Modifier,
viewModel: AuthorViewModel = hiltViewModel()
) {
- val uiState: AuthorScreenUiState by viewModel.uiState.collectAsState()
+ val uiState: AuthorScreenUiState by viewModel.uiState.collectAsStateWithLifecycle()
AuthorScreen(
authorState = uiState.authorState,
newsState = uiState.newsState,
modifier = modifier,
onBackClick = onBackClick,
onFollowClick = viewModel::followAuthorToggle,
)
}
Подписка на Flow потоков с учетом жизненного цикла — рекомендуемый способ подписки на Android, чтобы другие части вашего приложения могли при необходимости высвобождать ресурсы.
Если вы создаете приложение Android с помощью Jetpack Compose, используйте для этого Composable функцию collectAsStateWithLifecycle.