diff --git a/app/src/main/java/com/google/samples/apps/nowinandroid/MainActivity.kt b/app/src/main/java/com/google/samples/apps/nowinandroid/MainActivity.kt index c4dea1f2b..de63dad5d 100644 --- a/app/src/main/java/com/google/samples/apps/nowinandroid/MainActivity.kt +++ b/app/src/main/java/com/google/samples/apps/nowinandroid/MainActivity.kt @@ -22,12 +22,21 @@ import androidx.activity.compose.setContent import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass import androidx.core.view.WindowCompat +import androidx.metrics.performance.JankStats import com.google.samples.apps.nowinandroid.ui.NiaApp import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject @OptIn(ExperimentalMaterial3WindowSizeClassApi::class) @AndroidEntryPoint class MainActivity : ComponentActivity() { + + @Inject + lateinit var lazyStats: dagger.Lazy + + @Inject + lateinit var jankFrameListener: JankStats.OnFrameListener + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -35,6 +44,22 @@ class MainActivity : ComponentActivity() { // including IME animations WindowCompat.setDecorFitsSystemWindows(window, false) - setContent { NiaApp(calculateWindowSizeClass(this)) } + setContent { + NiaApp(calculateWindowSizeClass(this)) + } + } + + override fun onResume() { + super.onResume() + isTrackingEnabled(true) + } + + override fun onPause() { + super.onPause() + isTrackingEnabled(false) + } + + private fun isTrackingEnabled(enabled: Boolean) { + lazyStats.get().isTrackingEnabled = enabled } } diff --git a/app/src/main/java/com/google/samples/apps/nowinandroid/di/JankStatsModule.kt b/app/src/main/java/com/google/samples/apps/nowinandroid/di/JankStatsModule.kt new file mode 100644 index 000000000..6d11a9f68 --- /dev/null +++ b/app/src/main/java/com/google/samples/apps/nowinandroid/di/JankStatsModule.kt @@ -0,0 +1,63 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.samples.apps.nowinandroid.di + +import android.app.Activity +import android.util.Log +import android.view.Window +import androidx.metrics.performance.JankStats +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.components.ActivityComponent +import java.util.concurrent.Executor +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.asExecutor + +@Module +@InstallIn(ActivityComponent::class) +object JankStatsModule { + @Provides + fun providesOnFrameListener(): JankStats.OnFrameListener { + return JankStats.OnFrameListener { frameData -> + // Make sure to only log janky frames. + if (frameData.isJank) { + // We're currently logging this but would better report it to a backend. + Log.v("NiA Jank", frameData.toString()) + } + } + } + + @Provides + fun providesWindow(activity: Activity): Window { + return activity.window + } + + @Provides + fun providesDefaultExecutor(): Executor { + return Dispatchers.Default.asExecutor() + } + + @Provides + fun providesJankStats( + window: Window, + executor: Executor, + frameListener: JankStats.OnFrameListener + ): JankStats { + return JankStats.createAndTrack(window, executor, frameListener) + } +} diff --git a/app/src/main/java/com/google/samples/apps/nowinandroid/navigation/NiaTopLevelNavigation.kt b/app/src/main/java/com/google/samples/apps/nowinandroid/navigation/NiaTopLevelNavigation.kt index f2404e88c..e76918eae 100644 --- a/app/src/main/java/com/google/samples/apps/nowinandroid/navigation/NiaTopLevelNavigation.kt +++ b/app/src/main/java/com/google/samples/apps/nowinandroid/navigation/NiaTopLevelNavigation.kt @@ -24,6 +24,7 @@ import androidx.compose.material.icons.outlined.Upcoming import androidx.compose.ui.graphics.vector.ImageVector import androidx.navigation.NavGraph.Companion.findStartDestination import androidx.navigation.NavHostController +import androidx.tracing.trace import com.google.samples.apps.nowinandroid.feature.foryou.R.string.for_you import com.google.samples.apps.nowinandroid.feature.foryou.navigation.ForYouDestination import com.google.samples.apps.nowinandroid.feature.interests.R.string.interests @@ -41,18 +42,20 @@ import com.google.samples.apps.nowinandroid.feature.interests.navigation.Interes class NiaTopLevelNavigation(private val navController: NavHostController) { fun navigateTo(destination: TopLevelDestination) { - navController.navigate(destination.route) { - // Pop up to the start destination of the graph to - // avoid building up a large stack of destinations - // on the back stack as users select items - popUpTo(navController.graph.findStartDestination().id) { - saveState = true + trace("Navigation: $destination") { + navController.navigate(destination.route) { + // Pop up to the start destination of the graph to + // avoid building up a large stack of destinations + // on the back stack as users select items + popUpTo(navController.graph.findStartDestination().id) { + saveState = true + } + // Avoid multiple copies of the same destination when + // reselecting the same item + launchSingleTop = true + // Restore state when reselecting a previously selected item + restoreState = true } - // Avoid multiple copies of the same destination when - // reselecting the same item - launchSingleTop = true - // Restore state when reselecting a previously selected item - restoreState = true } } } diff --git a/app/src/main/java/com/google/samples/apps/nowinandroid/ui/NiaApp.kt b/app/src/main/java/com/google/samples/apps/nowinandroid/ui/NiaApp.kt index 135634a31..20a2decb6 100644 --- a/app/src/main/java/com/google/samples/apps/nowinandroid/ui/NiaApp.kt +++ b/app/src/main/java/com/google/samples/apps/nowinandroid/ui/NiaApp.kt @@ -46,10 +46,12 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp +import androidx.navigation.NavController import androidx.navigation.NavDestination import androidx.navigation.NavDestination.Companion.hierarchy import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController +import com.google.samples.apps.nowinandroid.core.ui.JankMetricDisposableEffect import com.google.samples.apps.nowinandroid.core.ui.component.NiaBackground import com.google.samples.apps.nowinandroid.core.ui.theme.NiaTheme import com.google.samples.apps.nowinandroid.navigation.NiaNavHost @@ -62,6 +64,18 @@ import com.google.samples.apps.nowinandroid.navigation.TopLevelDestination fun NiaApp(windowSizeClass: WindowSizeClass) { NiaTheme { val navController = rememberNavController() + JankMetricDisposableEffect(navController) { metricsHolder -> + val listener = NavController.OnDestinationChangedListener { _, destination, _ -> + metricsHolder.state?.addState("Navigation", destination.route.toString()) + } + + navController.addOnDestinationChangedListener(listener) + + onDispose { + navController.removeOnDestinationChangedListener(listener) + } + } + val niaTopLevelNavigation = remember(navController) { NiaTopLevelNavigation(navController) } diff --git a/core-navigation/build.gradle.kts b/core-navigation/build.gradle.kts index d9449babc..9e9ab81ae 100644 --- a/core-navigation/build.gradle.kts +++ b/core-navigation/build.gradle.kts @@ -28,6 +28,7 @@ dependencies { api(libs.androidx.hilt.navigation.compose) api(libs.androidx.navigation.compose) + implementation(libs.androidx.tracing.ktx) implementation(libs.hilt.android) kapt(libs.hilt.compiler) } \ No newline at end of file diff --git a/core-ui/build.gradle.kts b/core-ui/build.gradle.kts index 7fade59be..3d47cb9ee 100644 --- a/core-ui/build.gradle.kts +++ b/core-ui/build.gradle.kts @@ -43,4 +43,6 @@ dependencies { api(libs.androidx.compose.ui.util) api(libs.androidx.compose.runtime) api(libs.androidx.compose.runtime.livedata) + api(libs.androidx.metrics) + api(libs.androidx.tracing.ktx) } \ No newline at end of file diff --git a/core-ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/JankStatsExtensions.kt b/core-ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/JankStatsExtensions.kt new file mode 100644 index 000000000..2ae7aa97a --- /dev/null +++ b/core-ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/JankStatsExtensions.kt @@ -0,0 +1,73 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.samples.apps.nowinandroid.core.ui + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.DisposableEffectResult +import androidx.compose.runtime.DisposableEffectScope +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.remember +import androidx.compose.ui.platform.LocalView +import androidx.metrics.performance.PerformanceMetricsState +import androidx.metrics.performance.PerformanceMetricsState.MetricsStateHolder +import kotlinx.coroutines.CoroutineScope + +/** + * Retrieves [PerformanceMetricsState.MetricsStateHolder] from current [LocalView] and + * remembers it until the View changes. + * @see PerformanceMetricsState.getForHierarchy + */ +@Composable +fun rememberMetricsStateHolder(): MetricsStateHolder { + val localView = LocalView.current + + return remember(localView) { + PerformanceMetricsState.getForHierarchy(localView) + } +} + +/** + * Convenience function to work with [PerformanceMetricsState] state. The side effect is + * re-launched if any of the [keys] value is not equal to the previous composition. + * @see JankMetricDisposableEffect if you need to work with DisposableEffect to cleanup added state. + */ +@Composable +fun JankMetricEffect( + vararg keys: Any?, + reportMetric: suspend CoroutineScope.(state: MetricsStateHolder) -> Unit +) { + val metrics = rememberMetricsStateHolder() + LaunchedEffect(metrics, *keys) { + reportMetric(metrics) + } +} + +/** + * Convenience function to work with [PerformanceMetricsState] state that needs to be cleaned up. + * The side effect is re-launched if any of the [keys] value is not equal to the previous composition. + */ +@Composable +fun JankMetricDisposableEffect( + vararg keys: Any?, + reportMetric: DisposableEffectScope.(state: MetricsStateHolder) -> DisposableEffectResult +) { + val metrics = rememberMetricsStateHolder() + DisposableEffect(metrics, *keys) { + reportMetric(this, metrics) + } +} diff --git a/feature-foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/AuthorsCarousel.kt b/feature-foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/AuthorsCarousel.kt index c75592511..1544d7dad 100644 --- a/feature-foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/AuthorsCarousel.kt +++ b/feature-foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/AuthorsCarousel.kt @@ -18,10 +18,8 @@ package com.google.samples.apps.nowinandroid.feature.foryou import androidx.compose.foundation.background import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height @@ -30,6 +28,7 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.sizeIn import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.selection.toggleable import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons @@ -41,6 +40,7 @@ import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.remember +import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -57,6 +57,9 @@ import coil.compose.AsyncImage import com.google.samples.apps.nowinandroid.core.model.data.Author import com.google.samples.apps.nowinandroid.core.model.data.FollowableAuthor import com.google.samples.apps.nowinandroid.core.ui.FollowButton +import com.google.samples.apps.nowinandroid.core.ui.JankMetricEffect +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.combine @Composable fun AuthorsCarousel( @@ -64,11 +67,25 @@ fun AuthorsCarousel( onAuthorClick: (String, Boolean) -> Unit, modifier: Modifier = Modifier ) { - LazyRow( - modifier = modifier, - contentPadding = PaddingValues(24.dp), - horizontalArrangement = Arrangement.spacedBy(24.dp) - ) { + val lazyListState = rememberLazyListState() + + JankMetricEffect(lazyListState) { metricsHolder -> + combine( + snapshotFlow { lazyListState.isScrollInProgress }, + snapshotFlow { lazyListState.firstVisibleItemIndex } + ) { isScrollInProgress, firstVisibleItemIndex -> + if (isScrollInProgress) { + metricsHolder.state?.addState( + "ForYou:AuthorsCarousel:Scrolling", + "Index=$firstVisibleItemIndex" + ) + } else { + metricsHolder.state?.removeState("ForYou:AuthorsCarousel:Scrolling") + } + }.collect() + } + + LazyRow(modifier, lazyListState) { items(items = authors, key = { item -> item.author.id }) { followableAuthor -> AuthorItem( author = followableAuthor.author, 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 1bce189a5..f6bfc63bf 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 @@ -44,7 +44,9 @@ import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyHorizontalGrid import androidx.compose.foundation.lazy.grid.items +import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.shape.CornerSize import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons @@ -63,6 +65,7 @@ import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -86,6 +89,7 @@ import com.google.samples.apps.nowinandroid.core.model.data.NewsResource import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType.Video import com.google.samples.apps.nowinandroid.core.model.data.SaveableNewsResource import com.google.samples.apps.nowinandroid.core.model.data.Topic +import com.google.samples.apps.nowinandroid.core.ui.JankMetricEffect import com.google.samples.apps.nowinandroid.core.ui.LoadingWheel import com.google.samples.apps.nowinandroid.core.ui.NewsResourceCardExpanded import com.google.samples.apps.nowinandroid.core.ui.component.NiaFilledButton @@ -96,6 +100,8 @@ import com.google.samples.apps.nowinandroid.core.ui.icon.NiaIcons import com.google.samples.apps.nowinandroid.core.ui.theme.NiaTheme import com.google.samples.apps.nowinandroid.core.ui.theme.NiaTypography import kotlin.math.floor +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.combine import kotlinx.datetime.Instant @Composable @@ -166,7 +172,25 @@ fun ForYouScreen( else -> floor(maxWidth / 300.dp).toInt().coerceAtLeast(1) } + val lazyListState = rememberLazyListState() + JankMetricEffect(lazyListState) { metricsHolder -> + combine( + snapshotFlow { lazyListState.isScrollInProgress }, + snapshotFlow { lazyListState.firstVisibleItemIndex }, + ) { isScrollInProgress, firstVisibleItemIndex -> + if (isScrollInProgress) { + metricsHolder.state?.addState( + "ForYou:Feed:Scrolling", + "index=$firstVisibleItemIndex" + ) + } else { + metricsHolder.state?.removeState("ForYou:Feed:Scrolling") + } + }.collect() + } + LazyColumn( + state = lazyListState, modifier = Modifier.fillMaxSize(), ) { InterestsSelection( @@ -297,7 +321,25 @@ private fun TopicSelection( onTopicCheckedChanged: (String, Boolean) -> Unit, modifier: Modifier = Modifier ) { + val lazyGridState = rememberLazyGridState() + JankMetricEffect(lazyGridState) { metricsHolder -> + combine( + snapshotFlow { lazyGridState.isScrollInProgress }, + snapshotFlow { lazyGridState.firstVisibleItemIndex }, + ) { isScrollInProgress, firstVisibleItemIndex -> + if (isScrollInProgress) { + metricsHolder.state?.addState( + "ForYou:TopicSelection:Scrolling", + "index=$firstVisibleItemIndex" + ) + } else { + metricsHolder.state?.removeState("ForYou:TopicSelection:Scrolling") + } + }.collect() + } + LazyHorizontalGrid( + state = lazyGridState, rows = GridCells.Fixed(3), horizontalArrangement = Arrangement.spacedBy(12.dp), verticalArrangement = Arrangement.spacedBy(12.dp), 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 7be087ccb..3a1c3ac7b 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 @@ -36,6 +36,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel +import com.google.samples.apps.nowinandroid.core.ui.JankMetricDisposableEffect import com.google.samples.apps.nowinandroid.core.ui.LoadingWheel import com.google.samples.apps.nowinandroid.core.ui.component.NiaTab import com.google.samples.apps.nowinandroid.core.ui.component.NiaTabRow @@ -50,7 +51,6 @@ fun InterestsRoute( ) { val uiState by viewModel.uiState.collectAsState() val tabState by viewModel.tabState.collectAsState() - InterestsScreen( uiState = uiState, tabState = tabState, @@ -61,6 +61,14 @@ fun InterestsRoute( switchTab = viewModel::switchTab, modifier = modifier ) + + JankMetricDisposableEffect(tabState) { metricsHolder -> + metricsHolder.state?.addState("Interests:TabState", "currentIndex:${tabState.currentIndex}") + + onDispose { + metricsHolder.state?.removeState("Interests:TabState") + } + } } @Composable diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5ac3c731f..af60436ed 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,12 +14,14 @@ androidxHiltNavigationCompose = "1.0.0" androidxLifecycle = "2.5.0-rc01" androidxMacroBenchmark = "1.1.0-rc03" androidxNavigation = "2.4.2" +androidxMetrics = "1.0.0-alpha01" androidxProfileinstaller = "1.2.0-beta01" androidxSavedState = "1.1.0" androidxStartup = "1.1.1" androidxWindowManager = "1.0.0" androidxTest = "1.4.0" androidxTestExt = "1.1.3" +androidxTracing = "1.1.0" androidxUiAutomator = "2.2.0" androidxWork = "2.7.1" coil = "2.0.0-rc01" @@ -69,6 +71,7 @@ androidx-dataStore-core = { group = "androidx.datastore", name = "datastore", ve 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-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" } androidx-profileinstaller = { group = "androidx.profileinstaller", name = "profileinstaller", version.ref = "androidxProfileinstaller" } androidx-savedstate-ktx = { group = "androidx.savedstate", name = "savedstate-ktx", version.ref= "androidxSavedState"} @@ -80,6 +83,7 @@ androidx-test-espresso-core = { group = "androidx.test.espresso", name = "espres androidx-test-runner = { group = "androidx.test", name = "runner", version.ref = "androidxTest" } androidx-test-rules = { group = "androidx.test", name = "rules", version.ref = "androidxTest" } androidx-test-uiautomator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "androidxUiAutomator" } +androidx-tracing-ktx = {group = "androidx.tracing", name="tracing-ktx", version.ref = "androidxTracing" } androidx-work-ktx = { group = "androidx.work", name = "work-runtime-ktx", version.ref = "androidxWork" } androidx-work-testing = { group = "androidx.work", name = "work-testing", version.ref = "androidxWork" } coil-kt = { group = "io.coil-kt", name = "coil", version.ref = "coil"} diff --git a/sync/build.gradle.kts b/sync/build.gradle.kts index 66b762118..02cae2c55 100644 --- a/sync/build.gradle.kts +++ b/sync/build.gradle.kts @@ -35,6 +35,7 @@ dependencies { implementation(libs.kotlinx.coroutines.android) + implementation(libs.androidx.tracing.ktx) implementation(libs.androidx.startup) implementation(libs.androidx.work.ktx) implementation(libs.hilt.ext.work) diff --git a/sync/src/main/java/com/google/samples/apps/nowinandroid/sync/workers/SyncWorker.kt b/sync/src/main/java/com/google/samples/apps/nowinandroid/sync/workers/SyncWorker.kt index 5b99e603b..ffb425d1e 100644 --- a/sync/src/main/java/com/google/samples/apps/nowinandroid/sync/workers/SyncWorker.kt +++ b/sync/src/main/java/com/google/samples/apps/nowinandroid/sync/workers/SyncWorker.kt @@ -18,6 +18,7 @@ package com.google.samples.apps.nowinandroid.sync.workers import android.content.Context import androidx.hilt.work.HiltWorker +import androidx.tracing.traceAsync import androidx.work.CoroutineWorker import androidx.work.ForegroundInfo import androidx.work.OneTimeWorkRequestBuilder @@ -59,15 +60,17 @@ class SyncWorker @AssistedInject constructor( appContext.syncForegroundInfo() override suspend fun doWork(): Result = withContext(ioDispatcher) { - // First sync the repositories in parallel - val syncedSuccessfully = awaitAll( - async { topicRepository.sync() }, - async { authorsRepository.sync() }, - async { newsRepository.sync() }, - ).all { it } + traceAsync("Sync", 0) { + // First sync the repositories in parallel + val syncedSuccessfully = awaitAll( + async { topicRepository.sync() }, + async { authorsRepository.sync() }, + async { newsRepository.sync() }, + ).all { it } - if (syncedSuccessfully) Result.success() - else Result.retry() + if (syncedSuccessfully) Result.success() + else Result.retry() + } } override suspend fun getChangeListVersions(): ChangeListVersions =