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
相关产品推荐
相关产品推荐

