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, если вы чувствуете, что с вас их достаточно.

Вот и все

Хотя этот простой тест был достаточно забавным, я до сих пор не тестировал его с еще большим количеством коллекционеров одновременно.

Если вы все-таки попробуете, напишите мне сообщение / оставьте комментарий со своими выводами. Кроме того, если вам понравились мемы, почему бы не использовать маленькую кнопку хлопка?

Полный исходный код проекта можно найти здесь.

Потом.