From 88054edf909de54e582850fcc461b5fefb550289 Mon Sep 17 00:00:00 2001 From: Manuel Vivo Date: Wed, 20 Jul 2022 21:27:20 +0200 Subject: [PATCH] Use collectAsStateWithLifecycle to safely collect uiState (#166) --- .../src/main/kotlin/AndroidFeatureConventionPlugin.kt | 1 + core-ui/build.gradle.kts | 1 + .../apps/nowinandroid/feature/author/AuthorScreen.kt | 6 ++++-- .../apps/nowinandroid/feature/foryou/ForYouScreen.kt | 8 +++++--- .../nowinandroid/feature/interests/InterestsScreen.kt | 8 +++++--- .../apps/nowinandroid/feature/topic/TopicScreen.kt | 8 ++++---- gradle/libs.versions.toml | 3 ++- 7 files changed, 22 insertions(+), 13 deletions(-) diff --git a/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt index 58ccca210..3cbb1d23f 100644 --- a/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt @@ -54,6 +54,7 @@ class AndroidFeatureConventionPlugin : Plugin { add("implementation", libs.findLibrary("coil.kt.compose").get()) add("implementation", libs.findLibrary("androidx.hilt.navigation.compose").get()) + add("implementation", libs.findLibrary("androidx.lifecycle.runtimeCompose").get()) add("implementation", libs.findLibrary("androidx.lifecycle.viewModelCompose").get()) add("implementation", libs.findLibrary("kotlinx.coroutines.android").get()) diff --git a/core-ui/build.gradle.kts b/core-ui/build.gradle.kts index 1d9624f25..597440d85 100644 --- a/core-ui/build.gradle.kts +++ b/core-ui/build.gradle.kts @@ -32,6 +32,7 @@ dependencies { // TODO : Remove these dependency once we upgrade to Android Studio Dolphin b/228889042 // These dependencies are currently necessary to render Compose previews debugImplementation(libs.androidx.customview.poolingcontainer) + debugImplementation(libs.androidx.lifecycle.runtimeCompose) debugImplementation(libs.androidx.lifecycle.viewModelCompose) debugImplementation(libs.androidx.savedstate.ktx) diff --git a/feature-author/src/main/java/com/google/samples/apps/nowinandroid/feature/author/AuthorScreen.kt b/feature-author/src/main/java/com/google/samples/apps/nowinandroid/feature/author/AuthorScreen.kt index 22c8e8c09..5d5addf09 100644 --- a/feature-author/src/main/java/com/google/samples/apps/nowinandroid/feature/author/AuthorScreen.kt +++ b/feature-author/src/main/java/com/google/samples/apps/nowinandroid/feature/author/AuthorScreen.kt @@ -38,7 +38,6 @@ import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -48,6 +47,8 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi +import androidx.lifecycle.compose.collectAsStateWithLifecycle import coil.compose.AsyncImage import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaBackground import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaFilterChip @@ -59,13 +60,14 @@ import com.google.samples.apps.nowinandroid.core.model.data.previewAuthors import com.google.samples.apps.nowinandroid.core.model.data.previewNewsResources import com.google.samples.apps.nowinandroid.core.ui.newsResourceCardItems +@OptIn(ExperimentalLifecycleComposeApi::class) @Composable fun AuthorRoute( onBackClick: () -> Unit, modifier: Modifier = Modifier, viewModel: AuthorViewModel = hiltViewModel(), ) { - val uiState: AuthorScreenUiState by viewModel.uiState.collectAsState() + val uiState: AuthorScreenUiState by viewModel.uiState.collectAsStateWithLifecycle() AuthorScreen( authorState = uiState.authorState, diff --git a/feature-foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt b/feature-foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt index 5b0222cdd..20c0f64bc 100644 --- a/feature-foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt +++ b/feature-foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt @@ -63,7 +63,6 @@ import androidx.compose.material3.windowsizeclass.WindowSizeClass import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -84,6 +83,8 @@ import androidx.compose.ui.util.trace import androidx.core.content.ContextCompat import androidx.core.view.doOnPreDraw import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi +import androidx.lifecycle.compose.collectAsStateWithLifecycle import coil.compose.AsyncImage import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaFilledButton import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaGradientBackground @@ -102,14 +103,15 @@ import com.google.samples.apps.nowinandroid.core.ui.NewsResourceCardExpanded import com.google.samples.apps.nowinandroid.core.ui.TrackScrollJank import kotlin.math.floor +@OptIn(ExperimentalLifecycleComposeApi::class) @Composable fun ForYouRoute( windowSizeClass: WindowSizeClass, modifier: Modifier = Modifier, viewModel: ForYouViewModel = hiltViewModel() ) { - val interestsSelectionState by viewModel.interestsSelectionState.collectAsState() - val feedState by viewModel.feedState.collectAsState() + val interestsSelectionState by viewModel.interestsSelectionState.collectAsStateWithLifecycle() + val feedState by viewModel.feedState.collectAsStateWithLifecycle() ForYouScreen( windowSizeClass = windowSizeClass, modifier = modifier, diff --git a/feature-interests/src/main/java/com/google/samples/apps/nowinandroid/feature/interests/InterestsScreen.kt b/feature-interests/src/main/java/com/google/samples/apps/nowinandroid/feature/interests/InterestsScreen.kt index 390fc8019..c0961919e 100644 --- a/feature-interests/src/main/java/com/google/samples/apps/nowinandroid/feature/interests/InterestsScreen.kt +++ b/feature-interests/src/main/java/com/google/samples/apps/nowinandroid/feature/interests/InterestsScreen.kt @@ -24,7 +24,6 @@ import androidx.compose.foundation.layout.windowInsetsTopHeight import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -32,6 +31,8 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaBackground import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaLoadingWheel import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaTab @@ -45,6 +46,7 @@ import com.google.samples.apps.nowinandroid.core.model.data.previewAuthors import com.google.samples.apps.nowinandroid.core.model.data.previewTopics import com.google.samples.apps.nowinandroid.core.ui.JankMetricDisposableEffect +@OptIn(ExperimentalLifecycleComposeApi::class) @Composable fun InterestsRoute( modifier: Modifier = Modifier, @@ -52,8 +54,8 @@ fun InterestsRoute( navigateToTopic: (String) -> Unit, viewModel: InterestsViewModel = hiltViewModel() ) { - val uiState by viewModel.uiState.collectAsState() - val tabState by viewModel.tabState.collectAsState() + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val tabState by viewModel.tabState.collectAsStateWithLifecycle() InterestsScreen( uiState = uiState, diff --git a/feature-topic/src/main/java/com/google/samples/apps/nowinandroid/feature/topic/TopicScreen.kt b/feature-topic/src/main/java/com/google/samples/apps/nowinandroid/feature/topic/TopicScreen.kt index c3fe5e332..08cd7a8ad 100644 --- a/feature-topic/src/main/java/com/google/samples/apps/nowinandroid/feature/topic/TopicScreen.kt +++ b/feature-topic/src/main/java/com/google/samples/apps/nowinandroid/feature/topic/TopicScreen.kt @@ -17,7 +17,6 @@ package com.google.samples.apps.nowinandroid.feature.topic import androidx.annotation.VisibleForTesting -import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -38,7 +37,6 @@ import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -46,6 +44,8 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi +import androidx.lifecycle.compose.collectAsStateWithLifecycle import coil.compose.AsyncImage import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaBackground import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaFilterChip @@ -58,13 +58,14 @@ import com.google.samples.apps.nowinandroid.core.ui.newsResourceCardItems import com.google.samples.apps.nowinandroid.feature.topic.R.string import com.google.samples.apps.nowinandroid.feature.topic.TopicUiState.Loading +@OptIn(ExperimentalLifecycleComposeApi::class) @Composable fun TopicRoute( onBackClick: () -> Unit, modifier: Modifier = Modifier, viewModel: TopicViewModel = hiltViewModel(), ) { - val uiState: TopicScreenUiState by viewModel.uiState.collectAsState() + val uiState: TopicScreenUiState by viewModel.uiState.collectAsStateWithLifecycle() TopicScreen( topicState = uiState.topicState, @@ -75,7 +76,6 @@ fun TopicRoute( ) } -@OptIn(ExperimentalFoundationApi::class) @VisibleForTesting @Composable internal fun TopicScreen( diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index acd76bb9c..0d949136c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,7 +12,7 @@ androidxCustomView = "1.0.0-rc01" androidxDataStore = "1.0.0" androidxEspresso = "3.4.0" androidxHiltNavigationCompose = "1.0.0" -androidxLifecycle = "2.5.0-rc02" +androidxLifecycle = "2.6.0-alpha01" androidxMacroBenchmark = "1.1.0" androidxNavigation = "2.5.0" androidxMetrics = "1.0.0-alpha01" @@ -72,6 +72,7 @@ androidx-customview-poolingcontainer = { group = "androidx.customview", name = " androidx-dataStore-core = { group = "androidx.datastore", name = "datastore", version.ref = "androidxDataStore" } androidx-dataStore-preferences = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "androidxDataStore" } androidx-hilt-navigation-compose = { group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "androidxHiltNavigationCompose" } +androidx-lifecycle-runtimeCompose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "androidxLifecycle" } androidx-lifecycle-viewModelCompose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidxLifecycle" } androidx-metrics = { group = "androidx.metrics", name = "metrics-performance", version.ref = "androidxMetrics" } androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "androidxNavigation" }