Поток не наблюдает за изменениями переменной

Мне нужно, чтобы при изменении переменной CustomSingleton.customVar, хранящейся в singleton, мой составной объект перекомпоновывался для изменения текущего экрана в navhost. Итак, я сделал это на viewmodel экрана, на котором есть navhost:

val currentScreenId = MutableStateFlow<Int>(CustomSingleton.customVar)

val currentScreenIdState: StateFlow<Int> = currentScreenId.stateIn(
    viewModelScope,
    SharingStarted.WhileSubscribed(5_000),
    CustomSingleton.customVar
)

Я слушаю значение потока в составном элементе, используя этот код:

val currentSectionId by viewModel.currentScreenIdState.collectAsStateWithLifecycle()

Затем какая-то другая часть кода изменяет переменную в синглтоне:

CustomSingleton.customVar = 1

Проблема в том, что компоновка не перекомпонуется, поэтому изменение переменной не наблюдается.

Почему?

Помимо того, что говорят ответы, нет смысла вызывать stateIn в StateFlow. Вы конвертируете StateFlow в другой StateFlow, что бессмысленно.

Tenfour04 21.08.2024 04:09
1
1
53
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Потоки состояний работают не так. Они не делают так, чтобы вы получали уведомление, когда кто-то обновляет значение. Он создает поток с текущим состоянием — по сути, он запоминает последнее отправленное в него значение и немедленно отправляет его новому подписчику. Значение, которое вы передаете при вызове MutableStateFlow или stateIn, — это всего лишь начальное значение текущего состояния, оно не устанавливает какого-либо наблюдения за переменной в будущем.

Чтобы получить то, что вы хотите, избавьтесь от этого потока состояний. Сделайте CustomSignleton.customeVar самим StateFlow и установите его, установив CustomSingleton.customVar.value = 1.

Ответ принят как подходящий

Как уже отмечал Гейб Сечан, параметр MutableStateFlow() является начальным значением, он не отслеживается автоматически при изменениях.

Если вы хотите наблюдать CustomSingleton.customVar за изменениями, это само по себе должно быть потоком. Предполагая, что customVar в настоящее время объявлен следующим образом в CustomSingleton:

var customVar = 0

Затем вы можете изменить его на это:

val customVar = MutableStateFlow(0)

0 здесь — начальное значение, замените его на то, что хотите. Поскольку теперь это Flow, а не Int, изменение значения выполняется следующим образом:

customVar.value = 42

Теперь, покончив с этим, вы можете изменить код модели представления на следующее:

val currentScreenIdState: StateFlow<Int> = CustomSingleton.customVar.asStateFlow()

И все. Всякий раз, когда значение customVar изменяется, ваш поток currentScreenIdState генерирует новое значение, которое затем собирается вашим пользовательским интерфейсом.


Ключевым моментом является использование потоков в источнике для всего, что вам нужно отслеживать на предмет изменений. MutableStateFlow ведет себя аналогично переменной, поскольку всегда имеет одно значение. Но вы также можете использовать любой другой тип потока (тогда вам, возможно, придется снова использовать stateIn в модели представления вместо asStateFlow). Что лучше, зависит от того, откуда на самом деле происходят изменения.

Если это явно задано в некоторых других частях вашего кода, хорошим выбором будет MutableStateFlow. Когда измененное значение поступает из обратного вызова, вы можете преобразовать его в поток с помощью callbackFlow. Когда данные поступают из какого-либо другого API, например базы данных, он уже может поддерживать потоки «из коробки». Например, Room можно легко настроить для возврата всех результатов базы данных в виде потока.

Большое спасибо. Является ли хорошей практикой иметь поток состояний в одиночном элементе и получать к нему доступ в модели представления, чтобы вносить изменения на экране в зависимости от значения этого потока состояний?

NullPointerException 21.08.2024 16:47

Если вам нужно только значение в модели представления, вам следует поместить его непосредственно туда.

Leviathan 21.08.2024 18:22

ну это сложно объяснить, но переменная получается не в скрине, получается в синглтоне, это специальное приложение со специальными реквизитами, поэтому переменная у меня в этом синглтоне

NullPointerException 21.08.2024 22:18

Другие вопросы по теме