Введение в потоки

Версия Home API Kotlin использует потоки — функцию языка Kotlin, которая предоставляет мощные возможности для обработки асинхронных потоков данных, включая преобразование, фильтрацию, сопоставление, преобразование в коллекции и обратно и т. д.

Сопрограммы тесно связаны с потоками и предоставляют элегантную абстракцию для написания асинхронного кода и освобождают разработчика от необходимости явно писать процедуры обратного вызова. Потоки работают рука об руку с сопрограммами, служа способом асинхронного получения данных из сопрограмм, без необходимости ждать завершения функции или потока.

Данные извлекаются из потока потребителем в процессе, называемом сбором . В потоках Kotlin есть функция collect() , которую можно использовать для этой цели. То, что происходит в потоке во время сбора данных, зависит от типа потока.

Потоки Kotlin ( Flow<T> ) по умолчанию являются холодными , а это означает, что код построителя потоков создает данные только при вызове collect() . Горячий поток, напротив, создает данные немедленно, буферизуя их в памяти, как очередь, на случай, если данные будут использованы. Поскольку данные хранятся в памяти, горячий поток считается сохраняющим состояние.

Потоки можно преобразовать из холодных в горячие с помощью оператора shareIn (см. «Как сделать холодные потоки горячими с помощью shareIn »). Вы также можете использовать SharedFlow или StateFlow , чтобы превратить холодный поток в горячий.

Как пример приложения использует потоки

В примере приложения используются модели представлений в Jetpack Compose, подключенные к потокам Home API. Многие из примеров элементов пользовательского интерфейса приложения управляются состоянием, но с ними можно взаимодействовать. Пример приложения также сочетает состояние устройств с «оптимистическим» состоянием пользовательского интерфейса для удобства работы пользователя в реальном времени. Термин «оптимистичный» означает, что приложение предполагает, что данное действие выполнено успешно, и немедленно обновляет пользовательский интерфейс, чтобы отразить ожидаемый результат, не дожидаясь подтверждения. Если окажется, что действие не удалось, пользовательский интерфейс обновляется, чтобы отразить истинное состояние.

В примере приложения потоки создаются для каждого уровня модели представления (структур, помещений, устройств). Например, это делается для структур со следующим вызовом в GlobalViewModel.kt :

  fun getStructuresState(): StateFlow<List<StructureModel>?> =
    homeClient
      .structures()
      .map { structures -> structures.map { StructureModel(it.name, it) }.sortedBy { it.name } }
      .handleErrors()
      .flowOn(Dispatchers.IO)
      .stateIn(scope = viewModelScope, started = SharingStarted.WhileSubscribed(), null)

emitAll() собирает все значения из данного потока и отправляет их в сборщик. stateIn() передает последнее переданное значение из одного работающего экземпляра восходящего потока нескольким нисходящим подписчикам. Дополнительную информацию см. в справочнике kotlinx.coroutines.flow .

Реактивный ранец

Чтобы хранить объекты потока в локальной памяти и предотвратить их завершение, используйте API remember Kotlin.

В Jetpack Compose, если вы используете это с collectAsStateWithLifecycle() , Jetpack автоматически управляет подпиской и отменой подписки на потоки в зависимости от того, находится ли пользовательский интерфейс приложения, показывающий это состояние, на переднем плане или нет.

Это можно сделать с помощью простого вызова в примере приложения. Использование функции getStructuresState() показанной ранее:

val structuresList by
    remember(globalViewModel) { globalViewModel.getStructuresState() }.collectAsStateWithLifecycle()

Теперь, когда какое-либо состояние структуры изменится (например, name ), функция Composable, которая его использует, автоматически отразит это обновленное состояние. В примере приложения это функция HomeActivityContent() .

Ресурсы

Дополнительную информацию о Kotlin, потоках, сопрограммах и Jetpack Compose см. на следующих ресурсах: