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

navController.navigate()在lambda回调中调用不生效问题

问题场景

点击按钮后需要先发起POST请求,等请求完成后携带网络加载得到的bundle打开目标Fragment。
在不带bundle的测试场景下发现:把navigate方法写在网络请求回调中时无法正常跳转,但logcat可以正常打印Got login response日志,证明回调确实被执行;如果把changeFragmentToMessages()移到网络请求代码外侧、放在请求发起前调用,跳转功能完全正常,点击按钮就能打开目标Fragment。
对应代码如下:

fun changeFragmentToMessages() {
    findNavController().navigate(R.id.action_loginFragment_to_messagesFragment)
}


private fun loginButtonClicked(v:View) {
    val login = inputLogin.text.toString()
    val password = inputPassword.text.toString()

    Fuel
        .post(ReqUtils.getUri("loadchats"))
        .body(
            JSONObject(
                mapOf(
                    "login" to login,
                    "password" to password
                )
            ).toString()
        )
        .header("content-type", "application/json")
        .response {
            request, response, result ->
            Log.d("HTTP", "Got login response")
            changeFragmentToMessages()
        }
}
问题原因

Fuel的response回调默认执行在子工作线程,Android系统要求所有UI相关操作(包括Navigation组件的页面导航操作)必须在主线程调用,子线程里直接调navigate不会触发正常跳转。
把跳转逻辑移到请求外层时,代码运行在按钮点击事件的主线程上下文里,所以可以正常工作。

解决方案

核心是把导航逻辑切到主线程执行,后续携带请求返回的bundle参数跳转也遵循这个规则即可,常见实现方式有两种:

  • 利用当前点击的View对象直接切主线程,不需要额外引入依赖,改动最小:
.response { request, response, result ->
    Log.d("HTTP", "Got login response")
    // 切到主线程执行导航
    v.post {
        // 后续需要传参时,在这里解析result生成Bundle传入即可
        // 示例:val chatBundle = bundleOf("chatData" to 解析后的返回数据)
        // findNavController().navigate(R.id.action_loginFragment_to_messagesFragment, chatBundle)
        changeFragmentToMessages()
    }
}
  • 如果项目使用Kotlin协程,可以引入Fuel的协程扩展,在生命周期感知的协程作用域中处理请求,天然在主线程返回结果:
// 先引入对应协程扩展依赖
// implementation "com.github.kittinunf.fuel:fuel-coroutines:<当前使用的Fuel版本号>"
private fun loginButtonClicked(v:View) {
    val login = inputLogin.text.toString()
    val password = inputPassword.text.toString()
    
    lifecycleScope.launch {
        val (request, response, result) = Fuel
            .post(ReqUtils.getUri("loadchats"))
            .body(
                JSONObject(
                    mapOf(
                        "login" to login,
                        "password" to password
                    )
                ).toString()
            )
            .header("content-type", "application/json")
            .awaitResponse()
        Log.d("HTTP", "Got login response")
        // lifecycleScope默认在主线程启动,直接执行导航即可
        changeFragmentToMessages()
    }
}

注意:所有和UI、组件导航相关的操作,都不要在子线程直接调用,否则会出现不生效、崩溃等不可预期的问题。

内容的提问来源于stack exchange,提问作者Nikitiy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 11:57:13