Android 12下okhttp3调用addHeader报非空参数为null的崩溃问题排查
根因分析
- 竞态条件问题
你代码中多次调用userDataManager的读取方法,这一系列操作不具备原子性。如果两次读取之间有其他线程(比如用户登出、token清理逻辑)修改了userDataManager中的存储数据,就会出现前置判断非空,但后续读取实际返回空的情况。 - 平台类型隐式空值
如果UserDataManager.getAuthToken()、RefreshTokenService.getNewTokenUsingRefreshToken()是Java实现的方法,且没有添加@NonNull注解,Kotlin会将返回值识别为平台类型,允许你赋值给声明为非空的accessToken变量。当方法实际返回null时,运行时accessToken就会变成null,传入OkHttp的addHeader方法时就会触发Kotlin的非空参数检查,抛出你遇到的异常。该问题仅在特定触发条件下才会出现,所以本地测试难以复现。 - 刷新token异常未捕获
你在runBlocking中执行刷新token逻辑时没有捕获异常,如果刷新请求出现网络错误、token无效等异常,会导致后续逻辑执行异常,甚至出现预期外的空值。
修复方案
- 消除竞态条件,统一添加空值兜底
一次性读取用户数据避免多次读取的不一致问题,同时对所有可能返回空的取值逻辑做强制兜底,确保最终传给addHeader的参数绝对非空,参考修改后的代码:
class RequestInterceptor @Inject constructor( private val userDataManager: UserDataManager, private val refreshTokenService: RefreshTokenService ) : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { // 一次性读取用户数据,避免多次读取的竞态问题 val userAccessData = userDataManager.getUserAccessData() var accessToken = "" if (userAccessData != null) { val authToken = userDataManager.getAuthToken() ?: "" accessToken = "Bearer $authToken" if (userDataManager.isAuthTokenExpired()) { accessToken = "" try { runBlocking { val newToken = refreshTokenService.getNewTokenUsingRefreshToken() ?: "" accessToken = "Bearer $newToken" } } catch (e: Exception) { // 刷新token异常兜底 accessToken = "" } } } val original = chain.request() val builder = original.newBuilder() .method(original.method, original.body) // 最后再加一层兜底,确保header值绝对非空 .addHeader("Authorization", accessToken.takeIf { it.isNotEmpty() } ?: "") val newRequest = builder.build() return chain.proceed(newRequest) } }
- 统一OkHttp依赖版本
检查项目依赖树,确保所有模块引入的OkHttp版本一致,避免编译期和运行期的OkHttp版本不同,导致方法参数非空校验逻辑不匹配。 - Android 12适配调整
如果你的userDataManager底层用的是SharedPreferences,建议替换为DataStore。Android 12对SharedPreferences的异步提交、跨进程读取逻辑做了变更,容易出现数据读取不一致的问题,刚好可能触发空值场景。
定位建议
如果需要进一步确认问题,可以在addHeader调用前增加日志,打印accessToken的实际值和类型,崩溃后通过Firebase日志即可确认空值的来源:
Timber.d("Authorization value: $accessToken, isNull: ${accessToken == null}")
内容的提问来源于stack exchange,提问作者Craxx
相关产品推荐
相关产品推荐

