Множественные рекомпозиции запускаются при использовании метода CollectAsStateWithLifecycle() в составной функции.Android

Форум для тех, кто программирует под Android
Ответить
Anonymous
 Множественные рекомпозиции запускаются при использовании метода CollectAsStateWithLifecycle() в составной функции.

Сообщение Anonymous »


У меня есть действие Component с NavHost, которое имеет 2 составных объекта, представляющих 2 экрана. На первом компонуемом экране я собираю значение счетчика, которое представляет собой поток состояний, присутствующий в viewModel, который содержит значение счетчика. На втором экране я увеличиваю значение счетчика в модели представления в зависимости от успешного вызова API. Вызов API запускается нажатием кнопки, и после успеха я увеличиваю счетчик и открываю стек, возвращаясь на первый экран, чтобы показать увеличенное значение счетчика. ViewModel используется совместно двумя составными экранами.

Два способа собрать поток состояний, присутствующий в модели представления, в составной функции:
[*]viewModel.apiStatus.collectAsState() [*]viewModel.apiStatus.collectAsStateWithLifecycle()
Я понимаю, что рекомендуется использовать последний способ, поскольку он учитывает жизненный цикл. Но когда я собираю apiStatus с помощью CollectAsStateWithLifecycle() и попробуйте открыть стек, чтобы перейти на первый экран, второй экран снова и снова перекомпоновывает, собирает значения несколько раз и увеличивает счетчик более одного раза, т.е. метод handleResponse() вызывается несколько раз.

Любая помощь в определении того, почему возникает этот побочный эффект и как решить эту проблему, будет очень полезна для моего понимания композиции.

Пример кода
//вызывается из setContent{} в MainActivity @Композитный весело SampleNavSetup (sampleViewModel: SampleViewModel) { val navController = RememberNavController() NavHost(navController = navController, startDestination = SampleNav.FirstPage.route) { this.composable(route = SampleNav.FirstPage.route) { ПерваяСтраницаЭкран( ViewModel = образецViewModel, navHostController = navController ) } this.composable(route = SampleNav.SecondPage.route){ Вторая СтраницаЭкран( ViewModel = образецViewModel, navHostController = navController ) } } } @Композитный весело FirstPageScreen( модель просмотра: SampleViewModel, модификатор: Модификатор = Модификатор, навхостконтроллер: навхостконтроллер ) { Столбец( модификатор = modifier.fillMaxSize().padding(24.dp), HorizontalAlignment = Alignment.CenterHorizontally ) { val result = viewModel.getIncrementCounter().collectAsStateWithLifecycle() Текст( размер шрифта = 18.sp, FontWeight = FontWeight.W600, text = "Значение счетчика = ${result.value}" ) Кнопка( модификатор = Modifier.padding(top = 36.dp), onClick = { navHostController.navigate(SampleNav.SecondPage.route) } ) { Текст( text = "Перейти к следующему", цвет = Цвет.Белый ) } } } @Композитный забавный SecondPageScreen( модель просмотра: SampleViewModel, navHostController: NavHostController) { Box(modifier = Modifier.fillMaxSize()) { HandleApiResponse( модификатор = Modifier.padding(top = 96.dp).align(Alignment.Center), Модель просмотра = Модель просмотра, navHostController = navHostController ) Столбец(модификатор = Modifier.padding(24.dp).align(Alignment.TopCenter), HorizontalAlignment = Alignment.CenterHorizontally ) { Текст( размер шрифта = 18.sp, FontWeight = FontWeight.W600, text = "Сделать Fake API для увеличения счетчика" ) Кнопка( модификатор = Modifier.padding(top = 36.dp), onClick = { viewModel.doFakeApiCall() } ) { Текст( текст = «Нажми на меня», цвет = Цвет.Белый ) } } } } @Композитный весело HandleApiResponse( модификатор: Модификатор, модель просмотра: SampleViewModel, навхостконтроллер: навхостконтроллер ) { Log.d("Собрать вторую страницу","Собрать составную функцию ответа API-дескриптора") контекст val = LocalContext.current // не срабатывает несколько раз с помощью CollectAsState() //val ответ = viewModel.getApiStatus().collectAsState() /*Но при использовании метода CollectAsStateWithLifeCycle() наблюдается несколько раз, когда экран перестраивается несколько раз, и вызывается handleResponse несколько раз, не знаю причину*/ val ответ = viewModel.getApiStatus().collectAsStateWithLifecycle() когда (ответ.значение) { FakeApiState.Loading -> { CircularProgressIndicator(модификатор = modifier.size(32.dp), цвет = Цвет.Зеленый) } FakeApiState.Success -> { Log.d("Собрать вторую страницу","Собрать статус API") handleResponse (viewModel = viewModel, navHostController = navHostController) } FakeApiState.Fail -> { Toast.makeText(context, «Ошибка API», Toast.LENGTH_SHORT).show() } FakeApiState.Initial -> {} } } личное развлечениеResponse( модель просмотра: SampleViewModel, навхостконтроллер: навхостконтроллер ) { Log.d("Ответ второй страницы", "Собрать ответ дескриптора и popBackStack()") viewModel.incrementCounter() navHostController.popBackStack() viewModel.clearApiStatus() } класс SampleViewModel : ViewModel() { частный val _incrementCounter = MutableStateFlow (0) весело getIncrementCounter() = _incrementCounter.asStateFlow() частный val _apiStatus = MutableStateFlow(FakeApiState.Initial) весело getApiStatus() = _apiStatus.asStateFlow() весело приращениеCounter() { _incrementCounter.value = _incrementCounter.value + 1 } весело ClearApiStatus() { _apiStatus.value = FakeApiState.Initial } весело doFakeApiCall() { _apiStatus.value = FakeApiState.Loading viewModelScope.launch { задержка(1500л) _apiStatus.value = FakeApiState.Success } } }
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»