How should I handle "No internet connection" with Retrofit on Android

Viewed 107537

I'd like to handle situations when there is no internet connection. Usually I'd run:

ConnectivityManager cm =
    (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);

NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null &&
                  activeNetwork.isConnectedOrConnecting();

(from here) before sending the requests to the network and notify user if there were no internet connection.

From what I saw Retrofit does not handle this situation specifically. If there is no internet connection I'll just get RetrofitError with timeout as a reason.

If I'd like to incorporate this kind of check into every HTTP request with Retrofit, how should I do it? Or should I do it at all.

Thanks

Alex

8 Answers

Here's what I did on API 29 & API 30:

1. I created a simple WiFiService class that will hold the connectivityManager:

   class WifiService {
    private lateinit var wifiManager: WifiManager
    private lateinit var connectivityManager: ConnectivityManager

    companion object {
        val instance = WifiService()
    }

    fun initializeWithApplicationContext (context: Context) {
        wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager
        connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    }

    // Helper that detects if online
    fun isOnline(): Boolean {
        val capabilities = connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
        if (capabilities != null) {
            when {
                capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> return true
                capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> return true
                capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> return true
            }
        }
        return false
      }
   }

2. Create the ConnectivityInterceptor to check for internet access:

   class ConnectivityInterceptor: Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        if (!WifiService.instance.isOnline()) {
            throw IOException("No internet connection")
        } else {
            return chain.proceed(chain.request())
        }
     }
   }

3. Use it in Retrofit2 as follows:

  class RestApi {
    private val okHttpClient by lazy {
        OkHttpClient.Builder()
            .addInterceptor(ConnectivityInterceptor())
            .build()
    }

    // Define all the retrofit clients
    private val restApiClient by lazy {
        Retrofit.Builder()
            .baseUrl("http://localhost:10000")
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
     }

     // ...
  }

4. Finally initialize the WifiService as such:

class MainApplication: Application() {
  companion object {
    lateinit var instance:  MainApplication
  }

  override fun onCreate() {
    super.onCreate()
    instance = this

    setupServices()
  }

  private fun setupServices() {
    WifiService.instance.initializeWithApplicationContext(this)
  }
}

just do this you will notified even for issues like

UnknownHostException

,

SocketTimeoutException

and others.

 @Override public void onFailure(Call<List<BrokenGitHubRepo>> call, Throwable t) {  
if (t instanceof IOException) {
    Toast.makeText(ErrorHandlingActivity.this, "this is an actual network failure :( inform the user and possibly retry", Toast.LENGTH_SHORT).show();
    // logging probably not necessary
}
else {
    Toast.makeText(ErrorHandlingActivity.this, "conversion issue! big problems :(", Toast.LENGTH_SHORT).show();
    // todo log to some central bug tracking service
} }
Related