如何修复Supabase相关函数以避免抛出‘Job was cancelled’错误?
解决启动页检查Supabase登录时的"Job was canceled"错误
问题原因
"Job was canceled"错误通常是因为执行登录检查的协程在完成前被终止,常见场景:
- 启动页在协程完成网络请求前就跳转销毁,导致
viewModelScope内的协程被取消 auth.retrieveUser或auth.refreshCurrentSession这类网络请求耗时较长,超过启动页的默认停留时间
修复方案
1. 让启动页等待检查完成后再跳转
如果启动页是Activity,不要用固定时长跳转,而是监听ViewModel的状态变化后再执行跳转:
// SplashActivity示例代码 class SplashActivity : AppCompatActivity() { private val viewModel: SplashViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.startDestination.collect { destination -> val intent = when (destination) { Graph.MAIN -> Intent(this@SplashActivity, MainActivity::class.java) Screen.Onboarding1.route -> Intent(this@SplashActivity, OnboardingActivity::class.java) else -> Intent(this@SplashActivity, OnboardingActivity::class.java) } startActivity(intent) finish() } } } } }
2. 优化异常处理,区分协程取消与普通错误
补充捕获CancellationException,避免把协程取消误判为登录失败:
override suspend fun isUserLoggedIn(): Boolean { return try { val token = getToken().firstOrNull() if (token.isNullOrEmpty()) { false } else { auth.retrieveUser(token) auth.refreshCurrentSession() saveToken() true } } catch (e: CancellationException) { // 协程被取消时重新抛出,让上层处理 throw e } catch (e: Exception) { Log.e("UserRepository", "登录检查失败: ${e.message}") false } }
3. 简化检查逻辑,优先用本地会话
如果不需要每次启动都强制刷新会话,可以先检查本地缓存的会话是否有效,减少网络请求:
override suspend fun isUserLoggedIn(): Boolean { return try { // 先检查本地会话 val localSession = auth.currentSessionOrNull() if (localSession != null && !localSession.isExpired()) { true } else { val token = getToken().firstOrNull() if (token.isNullOrEmpty()) { false } else { auth.retrieveUser(token) val refreshedSession = auth.refreshCurrentSession() saveToken(refreshedSession.accessToken) // 保存最新token true } } } catch (e: CancellationException) { throw e } catch (e: Exception) { Log.e("UserRepository", "登录检查失败: ${e.message}") false } }
4. 临时方案:给启动页留足够的网络请求时间
如果需要保留固定时长的启动页,确保时长能覆盖网络请求的耗时:
// 修改SplashViewModel的初始化代码 init { viewModelScope.launch { delay(1200) // 预留1.2秒等待网络请求完成 _startDestination.value = if (userRepository.isUserLoggedIn()) { Graph.MAIN } else { Screen.Onboarding1.route } } }
内容的提问来源于stack exchange,提问作者user29314002
相关产品推荐
相关产品推荐

