Reputation: 653
I have NetworkUtils
to monitor the connection state:
object NetworkUtils {
lateinit var connectivityManager: ConnectivityManager
var isConnected = false; private set
private object NetworkCallback : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
isConnected = true
}
override fun onLost(network: Network) {
isConnected = false
}
}
fun init(context: Context) {
connectivityManager = context.getSystemService(ConnectivityManager::class.java)
}
fun isConnectedDeprecated(): Boolean {
val networkInfo = connectivityManager.activeNetworkInfo
return networkInfo?.isConnected == true
}
fun registerNetworkCallback() = connectivityManager.registerDefaultNetworkCallback(NetworkCallback)
fun unregisterNetworkCallback() = connectivityManager.unregisterNetworkCallback(NetworkCallback)
}
And Interceptor I use with Retrofit:
class MyInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
return try {
chain.proceed(chain.request())
} catch (e: IOException) {
throw if (NetworkUtils.isConnected()) {
ExceptionA()
} else {
ExceptionB()
}
}
}
}
The point is to know if IOException
thrown from request caused by no connection (ExceptionB
) or if it's some other network issue (ExceptionA
).
The issue is if I turn off WIFI on my device in the middle of the request I expect to get ExceptionB
, but sometimes I get ExceptionA
. Because when interceptor catches IOException
NetworkCallback
's onLost
isn't called yet.
I suspect that's because By default, the callback methods are called on the connectivity thread of your app, which is a separate thread used by ConnectivityManager.
(link)
And Retorfit runs interceptors on a different thread. So there's no any guaranteed order.
So is there a way to be sure that NetworkCallback
will be hit before interceptor will catch the exception?
I know we can pass in Handler
when registering the NetworkCallback
, and maybe that could help us to somehow run NetworkCallback
on the same thread as Retrofit interceptors. But I have no idea how to do it and it looks like a bit dirty solution.
Also, if check NetworkUtils.isConnectedDeprecated()
in interceptor instead of NetworkUtils.isConnected
then it works exactly like I want to. But documentation says:
Deprecated. Apps should instead use the ConnectivityManager.NetworkCallback API to learn about connectivity changes. These will give a more accurate picture of the connectivity state of the device and let apps react more easily and quickly to changes.
So it's not more quickly
if NetworkCallback
is called with some delay, huh?
Upvotes: 1
Views: 663