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

如何修复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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 20:12:12