Jetpack Compose导航动画致API重复调用的解决方案咨询
解决Jetpack Compose导航动画导致API重复调用的问题
问题场景
给Jetpack Compose的NavHost添加页面滑动导航动画后,路由组件的重组次数因动画触发增加,导致ViewModel中的API请求被重复调用。即使将请求放入ViewModel作用域,仍有部分重复请求无法彻底拦截。
核心代码如下:
NavHost配置
NavHost( navController = navController, startDestination = startDestination, enterTransition = { slideIntoContainer( towards = AnimatedContentTransitionScope.SlideDirection.Companion.Left, animationSpec = tween(TRANSITION_ANIMATION_DURATION) ) }, exitTransition = { slideOutOfContainer( towards = AnimatedContentTransitionScope.SlideDirection.Companion.Left, animationSpec = tween(TRANSITION_ANIMATION_DURATION) ) }, popEnterTransition = { slideIntoContainer( towards = AnimatedContentTransitionScope.SlideDirection.Companion.Right, animationSpec = tween(TRANSITION_ANIMATION_DURATION) ) }, popExitTransition = { slideOutOfContainer( towards = AnimatedContentTransitionScope.SlideDirection.Companion.Right, animationSpec = tween(TRANSITION_ANIMATION_DURATION) ) } ) { composable(route = AppDestination.Recent.destination) { nav -> AbcRoute(navController = navController, entry = nav) } }
路由组件代码
@Composable fun AbcRoute( navController: NavController, entry: NavBackStackEntry, ) { val objectA = entry.arguments?.getString(AppDestination.Abc.objectA)?.let { Json.decodeFromString<A>(it) } ?: return val viewModel = hiltViewModel<AbcViewModel>() val lifecycle = LocalLifecycleOwner.current.lifecycle val state = viewModel.enhanceState.collectAsStateWithLifecycle() LaunchedEffect(lifecycle) { viewModel.initialize(objectA) } }
解决方案
1. 优化LaunchedEffect的触发Key
当前用lifecycle作为LaunchedEffect的Key,导航动画过程中生命周期状态变化会导致多次进入代码块。改用**ViewModel实例+路由参数objectA**作为复合Key,确保仅在参数变化或ViewModel首次创建时执行初始化:
LaunchedEffect(viewModel, objectA) { viewModel.initialize(objectA) }
2. 在ViewModel内部控制请求执行次数
通过原子状态标记确保API请求仅执行一次,从根源避免重复调用:
class AbcViewModel : ViewModel() { private val hasInitialized = AtomicBoolean(false) fun initialize(objectA: A) { // 只有第一次调用时会进入逻辑 if (hasInitialized.compareAndSet(false, true)) { viewModelScope.launch { // 执行API请求逻辑 } } } }
3. 利用NavBackStackEntry的生命周期精准控制时机
NavBackStackEntry本身是LifecycleOwner,使用它的生命周期配合repeatOnLifecycle,确保只有页面真正进入STARTED状态(动画结束后)才触发初始化:
LaunchedEffect(entry) { entry.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.initialize(objectA) } }
内容的提问来源于stack exchange,提问作者Stevie
相关产品推荐
相关产品推荐

