StateFlow работает вхолостую. Разбираем SharingStartedПревращение
Flow в StateFlow через stateIn - стандартный паттерн в ViewModel. Но третий параметр (started) - это место, где утекают ресурсы процессора и сети.Смотрим типичный код:
val uiState: StateFlow<UiState> = repository.observeData()
.map { it.toUiState() }
.stateIn(
scope = viewModelScope,
started = SharingStarted.Eagerly, // 👈 Внимание сюда
initialValue = UiState.Loading
)
1.
SharingStarted.Eagerly - Режим "Зомби"Поток запускается сразу при создании класса (ViewModel).
Даже если UI еще не готов, даже если пользователь свернул приложение, даже если экран находится в бекстеке - этот поток активен.
Он качает данные из БД, маппит их, грузит процессор.
Вердикт: Используйте только если данные нужны всегда и немедленно (например, глобальный статус сети), и их обновление дешевое.
2.
SharingStarted.Lazily - Режим "Ленивец"Поток запускается, когда появляется первый подписчик.
Проблема: когда подписчики исчезают (User свернул app), поток не останавливается. Он продолжает молотить в фоне, обновляя кэш, который никто не видит.
Вердикт: Лучше, чем Eagerly, но все еще waste of resources.
3.
SharingStarted.WhileSubscribed(5000) - Выбор Сеньора 👑Поток активен только пока есть подписчики.
Но зачем там магическое число
5000 (5 секунд)?Сценарий: Поворот экрана (Configuration Change).
1. Activity умирает (Unsubscribe ❌).
2. Activity пересоздается (Subscribe ✅).
Между этими событиями проходит ~50-500 мс.
Если бы таймаута не было (0 мс), поток бы отменился и тут же перезапустился. Это значит:
• Лишний запрос в сеть/БД.
• Мигание UI (Loading -> Content).
Таймаут в 5 секунд дает "буферное время". Если подписчик вернулся в течение 5 секунд - поток даже не заметил разрыва. Данные остались горячими. Если не вернулся (пользователь ушел) - поток умирает и освобождает ресурсы.
⚠️ Нюанс: При использовании
WhileSubscribed, если пользователь ушел с экрана на 10 минут и вернулся, поток перезапустится с нуля (re-subscribe to upstream). Убедитесь, что ваш источник данных (Repository) готов к этому (например, имеет кэш), иначе юзер увидит спиннер.Чек-лист:
•
Eagerly: почти никогда.•
Lazily: если данные нужны "навсегда" после первого открытия.•
WhileSubscribed(5000): дефолт для UI.А вы используете константу
5000 или создаете свои стратегии? 👇✍️ @kotlin_lib