Kotlin Coroutines 1.4 уже здесь, как еще один шанс избавиться от скуки.
StateFlow
Представьте, что у нас есть фрагмент, который интересуется задачей todo из классического API JsonPlaceHolder.
Поскольку мы работаем с потоком, нам нужно запустить сопрограмму для его сбора.
Маленькая кнопка сообщит модели просмотра получить задачу, обновить поток и позволить нам собирать обновления, чтобы их можно было отобразить на экране.
Сама модель просмотра будет принадлежать действию, а не фрагменту, чтобы позже можно было провести эксперимент.
ViewModel:
- Обратите внимание
value = null
. Это начальное обновление, которое получит каждый, кто первым соберет этот поток. - В остальном довольно стандартные штучки. Перейдите в репозиторий и запросите задачу, затем обновите
todoStateFlow
, указав последнее значение. - Фрагмент, собирающий поток, получит обновление и отобразит его на экране.
- При вращении снова будет запущен метод
collect
и будет получено последнее известное значение. (или можно сказать последнее известное состояние 😅)
Кто-то может возразить, что LiveData не имеет большого смысла с StateFlow на картинке. Но опять же, подобные фразы можно услышать каждые вторые выходные, так что кто знает.
Вернемся к текущей задаче:
SharedFlow
Фрагмент (почти) остался прежним, но ViewModel теперь изменился:
replay = 0
означает, что после сбора обновления из потока оно больше никогда не будет отображаться (например, при повороте устройства).- Изменение
replay
на 1 как бы превратит это в StateFlow, так как последнее известное значение будет отправлено любому, кто запускает коллекцию. Дальнейшее увеличение этого числа также увеличит количество обновлений, которые получает любая «новая» коллекция соответственно.
Любой, кто использует MVVM более 5 минут, может вызвать необходимость выполнить одно действие, которое не будет повторяться при ротации. Так родились хаки SingleLiveData / SingleLiveEvent.
SharedFlow с нулевым воспроизведением, похоже, обходит это, но не без собственной проблемы:
Если коллекция не активна во время публикации значения в общем потоке, значение никогда не будет собрано фрагментом. Похоже, нам придется довольствоваться SingleLiveEvent
еще немного.
Несколько коллекций в одном SharedFlow
Что происходит, когда два отдельных фрагмента запускают коллекцию для одной и той же переменной SharedFlow?
Я никогда не читал документацию перед тем, как что-то попробовать (как и любой профессиональный пользователь клавиатуры), поэтому я не знал, чего ожидать, но это был приятный сюрприз! Оба фрагмента получают обновление и никогда не получат его снова, если они повернутся.
Ценители старых школьных автобусов заметят, что это похоже на Kotlin-y замену классическим EventBus / Otto, если вы чувствуете, что с вас их достаточно.
Вот и все
Хотя этот простой тест был достаточно забавным, я до сих пор не тестировал его с еще большим количеством коллекционеров одновременно.
Если вы все-таки попробуете, напишите мне сообщение / оставьте комментарий со своими выводами. Кроме того, если вам понравились мемы, почему бы не использовать маленькую кнопку хлопка?
Полный исходный код проекта можно найти здесь.
Потом.