Например, мое состояние пользовательского интерфейса выглядит так: это (это всего лишь пример, мой реальный код сложнее, но проблема та же):
Код: Выделить всё
data class UiState(
val showFavoriteBlock: Boolean,
val showRecentlyVisitedBlock: Boolean,
val showMostPopularBlock: Boolean,
val showSubscriptionBlock: Boolean,
val showFriendsBlock: Boolean,
val showRelatedBlock: Boolean,
val showLatestVisitedBlock: Boolean,
// There is 10+ same flags
// And here I have content for each block which starts loading after we receive flag
val favorites: Flow[*]>,
// 10+ flows for each block
)
Код: Выделить всё
@Composable
fun ExampleScreen(uiState: UiState){
// We don't show screen untill all flags will be received,
// flags itself are simple Booleans. But content for them is flow
LazyColumn {
// reading flag's value doesn't force recomposition
// because it's not State and can't be changed
if(uiState.showFavoriteBlock){
item{
// we sending flow, so updates in flow right now
// cannot force recomposition of screen
FavoritesBlock(uiState.favorites)
}
}
// 10+ items for each block
...
}
}
Код: Выделить всё
@Composable
fun RecentlyVisitedBlock(recentlyVisitedFlow: Flow) {
// recentlyVisited is State
val recentlyVisited by recentlyVisitedFlow.collectAsStateWithLifecycle()
Row {
// Here I'm reading state and this causes recomposition for all RecentlyVisitedBlock
// So recomposition happens only when we receive new data from flow
}
}
Все примеры в кодовых лабораториях, примерах компоновки реактивных ранцев и обучающих материалах содержат около 3-4 потоков. Но реальные приложения могут иметь около 20-30 (или даже больше) потоков, которые часто отправляют данные. Работать с потоками в фоновом режиме можно, но здесь я собираю их все в пользовательском интерфейсе.
Итак, мои вопросы:
- Можно ли иметь 10+ (или даже 20-30) потоков и собирать их независимо в компонуемые функции? Может ли это привести к проблемам с производительностью? Поскольку основной поток должен обрабатывать их все
- Я могу объединить все потоки в один внутри UiState, а затем использовать filterIsInstance для фильтрации и отправки каждому составному элементу только его данных. В этом случае у меня все еще есть 10+ вызовов функции CollectAsState, но, по крайней мере, вместо 10+ есть только один поток. Можно ли изменять потоки в пользовательском интерфейсе? Объединяйте их, сопоставляйте, фильтруйте.
- Я также могу изменить свой UiState и добавить поля состояния. Но в этом случае у меня будет более 10 потоков и более 10 похожих значений состояния. Похоже на плохой шаблон.
- Что, если я изменю свой экран на exampleScreen(uiState: Flow). В данном случае у меня есть только один поток с единственным вызовом CollectAsStateWithLifecycle, но при каждом изменении это будет вызывать перекомпоновку корня. Также я могу использовать DerivedStateOf и пропустить рекомпозицию некоторых дочерних элементов. Что лучше: иметь несколько потоков, которые независимо собирают и читают состояние, или иметь один поток, который вызывает перекомпозицию корня при каждом обновлении?
вам понадобится одно состояние для каждого значения (например: электронная почта, пароль,
загрузка, ошибка и т. д.). Проблема в том, что в вашей ViewModel и Composables будет много
состояний.
Подводя итог, первый вариант обеспечивает улучшенную читаемость, но приводит
к большее количество рекомпозиций. С другой стороны, второй
вариант лучше подходит для обработки рекомпозиций.
Как упоминалось в комментарии @Mehdi.ncb, я Я пытаюсь найти официальную рекомендацию Google и анализ производительности, чтобы решить, какую из них реализовать. 1) UiState уровня большого экрана (https://developer.android.com/jetpack/c ... n-ui-state) который генерирует класс данных с более чем 50 полями, который перекомпоновывает весь экран. Или 2) отдельные плавные поля с меньшим количеством перекомпоновок.
Подробнее здесь: https://stackoverflow.com/questions/765 ... ck-compose