地铁进隧道、电梯里、咖啡馆Wi-Fi突然掉线——这些场景下,App卡在加载页动不了,用户第一反应就是点返回再重进,其实问题可能出在没做ref="/tag/72/" style="color:#E3A3CF;font-weight:bold;">网络重连逻辑。
为什么需要手动实现重连?
Android系统本身不会替你重试HTTP请求。ConnectivityManager能告诉你当前有没有网,但不会帮你把失败的请求再发一遍;OkHttp默认也不重试超时或DNS失败的请求(除非你显式开启)。靠用户手动刷新,体验差,还容易漏掉关键数据同步。
一个轻量可靠的重连思路
不追求全自动兜底,而是聚焦「可感知、可控制、不滥用」:网络恢复时主动触发一次重试,失败后带退避策略再试1–2次,避免雪崩。
先监听网络状态变化:
private val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
private val callback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
// 网络已就绪,检查是否有待重连的请求
retryPendingRequests()
}
}注册监听(Android 7.0+推荐用registerDefaultNetworkCallback):
connectivityManager.registerDefaultNetworkCallback(callback)请求层怎么配合?
以OkHttp为例,在拦截器中记录失败请求(比如503、timeout、IOException),并缓存其Request和Callback:
class RetryInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
try {
return chain.proceed(chain.request())
} catch (e: IOException) {
enqueueForRetry(chain.request(), e)
throw e
}
}
}retryPendingRequests()里遍历缓存队列,用新OkHttpClient实例重新发起(避免复用已失效的连接):
fun retryPendingRequests() {
pendingRequests.forEach { (request, callback) ->
OkHttpClient().newCall(request).enqueue(callback)
}
pendingRequests.clear()
}加点人性化的细节
别一恢复网络就狂刷所有请求。给重连加个简单退避:第一次立即重试,第二次等1.5秒,第三次等3秒。用Handler.postDelayed实现即可。另外,对登录态过期、401响应这类业务错误,重连前先刷新token,否则重试也是白搭。
最后提醒一句:不是所有请求都适合重连。支付回调、短信验证码提交这类操作,重复触发有风险,必须服务端幂等支持,客户端只做提示,不自动重发。