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

Jetpack Compose中Token刷新失败回调未触发问题求助

Token刷新失败回调未触发的排查与解决方案

一、排查回调未触发的核心原因

1. 拦截器是否覆盖所有刷新失败场景

检查你的Interceptor代码,确认在Token刷新请求的所有失败分支(如401/5xx错误、网络超时、返回体为空)中,都明确调用了TokenRefreshErrorCallback的onTokenRefreshError方法:

// 示例拦截器中刷新Token的关键逻辑
val refreshResponse = tokenManager.refreshToken()
if (!refreshResponse.isSuccessful || refreshResponse.body()?.token.isNullOrEmpty()) {
    // 必须在所有失败分支调用回调
    tokenRefreshErrorCallback.onTokenRefreshError()
    // 终止后续请求,返回错误响应
    return@proceed Response.error(401, response.body()?.source() ?: Buffer())
}

2. 回调实例是否正确注入

检查依赖注入配置:

  • 自定义的TokenRefreshErrorCallback实现类是否被标记为单例(如Hilt的@Singleton)?
  • 拦截器/TokenManager初始化时,是否正确传入了同一个回调实例,而非每次创建新对象?

3. TokenManager的刷新逻辑是否正确抛出错误

确认TokenManager中处理刷新请求的代码,没有吞掉异常或错误状态。比如如果用协程处理网络请求,是否捕获了IOException、HttpException等异常,并在异常分支触发回调。

二、实现登录页跳转(类比iOS NotificationCenter)

Android中可以用SharedFlow(适配Jetpack Compose更友好)实现类似NotificationCenter的全局事件广播:

1. 创建全局事件管理器

@Singleton
class EventManager @Inject constructor(
    @ApplicationScope private val coroutineScope: CoroutineScope
) {
    // 定义登录跳转事件流,replay=0确保事件只发送给当前订阅者
    private val _loginNavigationEvent = MutableSharedFlow<Unit>(replay = 0)
    val loginNavigationEvent = _loginNavigationEvent.asSharedFlow()

    // 发送跳转事件(类比postNotification)
    fun triggerLoginNavigation() {
        coroutineScope.launch {
            _loginNavigationEvent.emit(Unit)
        }
    }
}

2. 在回调中触发跳转事件

修改你的回调实现类:

class TokenRefreshErrorImpl @Inject constructor(
    private val eventManager: EventManager,
    private val tokenManager: TokenManager
) : TokenRefreshErrorCallback {
    override fun onTokenRefreshError() {
        // 先清空本地无效Token
        tokenManager.clearAllTokens()
        // 触发登录跳转事件
        eventManager.triggerLoginNavigation()
    }
}

3. 在Compose导航宿主中订阅事件

@Composable
fun MainNavHost(navController: NavHostController, eventManager: EventManager) {
    // 订阅跳转事件(类比addObserver)
    LaunchedEffect(Unit) {
        eventManager.loginNavigationEvent.collect {
            navController.navigate("login") {
                // 清空返回栈,防止用户退回主页面
                popUpTo(navController.graph.startDestinationId) { inclusive = true }
            }
        }
    }

    NavHost(navController = navController, startDestination = "home") {
        composable("home") { HomeScreen() }
        composable("login") { LoginScreen() }
        // 其他页面路由...
    }
}

三、额外注意事项

  • 拦截器中执行Token刷新请求时,要在后台线程(如Dispatchers.IO)执行,避免阻塞主线程。
  • 跳转登录页前必须清空本地存储的Token和用户信息,防止后续请求携带无效凭证。
  • 若使用Hilt,需确保所有相关类(拦截器、TokenManager、EventManager)都正确配置了依赖注入注解(如@Module、@InstallIn)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 08:47:32