You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose导航动画致API重复调用的解决方案咨询

解决Jetpack Compose导航动画导致API重复调用的问题

问题场景

给Jetpack Compose的NavHost添加页面滑动导航动画后,路由组件的重组次数因动画触发增加,导致ViewModel中的API请求被重复调用。即使将请求放入ViewModel作用域,仍有部分重复请求无法彻底拦截。

核心代码如下:

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 15:26:28