大量请求后Coroutine与Retrofit出现空指针崩溃问题
空指针异常原因及修复方案
你的崩溃根本原因是滥用非空断言!!,加上未处理API请求失败的场景,具体问题点如下:
- 强制非空断言
!!触发NPE:代码中多处使用!!强制解包可空值(比如meta?.currentPage!!、recursiveResponse.body()?.meta!!),只要某次API请求返回的response.body()为null,或者返回的JSON中缺失meta字段,就会直接抛出空指针异常。当请求次数达到60+次时,大概率触发了API的限流机制(比如返回429 Too Many Requests),此时接口返回的不是正常数据,response.body()为null,!!直接引爆崩溃。 - 未处理请求失败场景:代码没有检查
response.isSuccessful,完全默认每次请求都能成功返回有效数据,忽略了网络波动、API限流、服务端错误等异常情况。
修复方案
替换所有!!为安全处理逻辑,同时增加请求成功校验,确保空值不会进入后续流程:
suspend fun getAllPlayers(): PlayersNetworkModel? { return withContext(Dispatchers.IO) { // 初始化请求校验 val initResponse = api.getAllPlayers() if (!initResponse.isSuccessful) { return@withContext null // 或抛出自定义异常 } val initBody = initResponse.body() ?: return@withContext null val data = mutableListOf<DataNetworkModel>().apply { addAll(initBody.data ?: emptyList()) } var currentMeta = initBody.meta ?: return@withContext null // 分页循环,全程避免强制解包 while (currentMeta.currentPage < currentMeta.totalPages && currentMeta.nextPage != null) { val nextPage = currentMeta.nextPage ?: break val pageResponse = api.getAllPlayers(nextPage) // 单页请求失败时,终止循环返回已有数据 if (!pageResponse.isSuccessful) break val pageBody = pageResponse.body() ?: break pageBody.data?.let { data.addAll(it) } currentMeta = pageBody.meta ?: break } PlayersNetworkModel(data, currentMeta) } }
关键修改点
- 移除所有
!!:用安全调用?.、空合并?:和显式空判断替代强制解包,从根源避免NPE。 - 增加请求成功校验:每次请求后检查
response.isSuccessful,确认HTTP状态码在200-299范围内再处理响应体。 - 容错式循环终止:如果某一页请求失败或返回数据不完整,直接终止循环,返回已获取的部分数据,避免整个流程崩溃。
- 初始化阶段提前校验:在进入循环前就检查初始请求的响应体和meta,避免无效循环。
内容的提问来源于stack exchange,提问作者Víctor Martín
相关产品推荐
相关产品推荐

