Android Google Credential Manager Kotlin API无网络时无限循环问题咨询
Google Credential Manager Kotlin API 无网络场景异常捕获问题解决
问题背景
使用Google Credential Manager Kotlin协程API实现Google登录时,正常场景下功能正常,但无网络环境中,getCredential方法不会抛出预期的IOException或其他可捕获异常,反而在后台持续输出[RequestTokenManager] getToken() -> NETWORK_ERROR日志,最终陷入无限循环导致UI无响应(ANR),所有捕获块均无法触发。目前临时改用Java API的getCredentialsAsync回调方案,但希望通过Kotlin API解决该问题。
可行解决方案
1. 提前检测网络状态
在调用getCredential前主动检查网络可用性,提前拦截无网络场景:
private fun isNetworkAvailable(context: Context): Boolean { val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager val activeNetwork = connectivityManager.activeNetwork ?: return false val networkCapabilities = connectivityManager.getNetworkCapabilities(activeNetwork) ?: return false return networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) }
在登录方法中添加前置判断:
fun googlePravesh(context:Context, aadhikaarik:Boolean = true) { Log.e(TAG, "googlePravesh: ") viewModelScope.launch { if (!isNetworkAvailable(context)) { kimPragat.value = false Toast.makeText(context, "网络不可用,请检查网络设置", Toast.LENGTH_SHORT).show() return@launch } // 原有options、request构建逻辑... try { kimPragat.value = true val credential = CredentialManager.create(context).getCredential(context, request).credential // 后续凭证处理逻辑... } catch (_: NoCredentialException) { kimPragat.value = false googlePravesh(context,false) } catch(e: IOException) { Log.e(TAG, "googlePravesh: api exception", e) kimPragat.value = false } catch (e:Exception) { kimPragat.value = false Toast.makeText(context,e.message, Toast.LENGTH_SHORT).show() } } }
2. 给协程添加超时机制
由于无网络时getCredential会无限重试,通过withTimeout强制终止调用,捕获超时异常来处理网络问题:
fun googlePravesh(context:Context, aadhikaarik:Boolean = true) { Log.e(TAG, "googlePravesh: ") viewModelScope.launch { val options = GetGoogleIdOption.Builder() .setFilterByAuthorizedAccounts(aadhikaarik) .setServerClientId("<server_id>") .setAutoSelectEnabled(true) .build() val request = GetCredentialRequest.Builder() .addCredentialOption(options) .build() try { kimPragat.value = true // 设置10秒超时,可根据需求调整 val credential = withTimeout(10_000) { CredentialManager.create(context).getCredential(context, request).credential } // 后续凭证处理逻辑... } catch (e: TimeoutCancellationException) { // 超时大概率对应网络异常 kimPragat.value = false Toast.makeText(context, "网络连接超时,请检查网络后重试", Toast.LENGTH_SHORT).show() } catch (_: NoCredentialException) { kimPragat.value = false googlePravesh(context,false) } catch(e: IOException) { Log.e(TAG, "googlePravesh: api exception", e) kimPragat.value = false } catch (e:Exception) { kimPragat.value = false Toast.makeText(context,e.message, Toast.LENGTH_SHORT).show() } } }
3. 组合方案(推荐)
将提前网络检测与协程超时结合,既提前拦截大部分无网络场景,又能处理检测后网络突变的情况,彻底避免ANR风险。
4. 反馈官方Bug
此问题属于Google Credential Manager Kotlin API的异常行为(未按预期抛出网络异常),建议在Google官方Issue渠道提交反馈,复现步骤如下:
- 环境:Android设备/模拟器,断开网络连接
- 操作:调用
CredentialManager.getCredential方法 - 现象:后台输出NETWORK_ERROR日志,无异常抛出,协程挂起进入无限循环
临时方案说明
改用Java API的getCredentialsAsync回调机制,无网络时会正常触发onFailure回调,可作为过渡方案,但Kotlin API的上述方案更符合协程编程习惯。
内容的提问来源于stack exchange,提问作者Manishoaham
相关产品推荐
相关产品推荐

