Libraries

Centralized Network Error Handling Retrofit

Welcome guys, You are looking for a centralized network solution in Android than you are in right place. In this android app tutorials, We’ll learn centralized network error handling Retrofit in Android. For doing that we’ll create a sample application that contains implementation Retrofit, RxJava with centralized network handling. Let’s see, how to do that.

Introduction

I give you a little bit idea about the approach, that I want to be implemented. You guys know well Retrofit, most popular networking library in Android. It very convenient and highly customizable based on the requirement and use cases.

Mostly we used Retrofit for Rest APIs call for showing the content from remote server. Every network call requires network connectivity to be accomplished. Most of times developers need to show proper error messages on the screen when a network goes down. Some professional apps show data from cache when it’s running out of internet or slow in connection. Basically, we make decisions based on use-case that we have to show data from cache or need to a proper screen. I will cover both use case in this tutorial.

1. Add dependencies in app build.gradle file

Open the app level build.gradle file and add Rxjava and Retrofit dependencies

  // Retrofit instance
  implementation 'com.squareup.retrofit2:retrofit:2.5.0'
  implementation 'com.squareup.retrofit2:converter-gson:2.4.0'

  // RxJava2 Dependencies
  implementation 'io.reactivex.rxjava2:rxjava:2.2.8'
  implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'

2. Do Retrofit configuration with OkHttp

Go to the network folder in source and create a new file named is CompRoot.

package com.example.internetconnection.di;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import com.example.internetconnection.DemoApp;
import com.example.internetconnection.network.ApiService;
import com.example.internetconnection.network.ConnectionInterceptor;
import com.example.internetconnection.network.ConnectionListener;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class CompRoot {
  private Retrofit retrofit;
  private static final String BASE_URL = "https://reqres.in/api/";

  public ApiService getService() {
    if (retrofit == null) {
      retrofit = new Retrofit
          .Builder()
          .baseUrl(BASE_URL)
          .client(provideOkHttpClient())
          .addConverterFactory(GsonConverterFactory.create())
          .build();
    }

    return retrofit.create(ApiService.class);
  }

  private OkHttpClient provideOkHttpClient() {
    OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
    httpClient.connectTimeout(30, TimeUnit.SECONDS);
    httpClient.readTimeout(30, TimeUnit.SECONDS);

    httpClient.addInterceptor(new ConnectionInterceptor() {
      @Override
      public boolean isInternetAvailable() {
        return CompRoot.this.isNetworkAvailable(DemoApp.getContext());
      }

      @Override
      public void onInternetUnavailable() {
        ConnectionListener.getInstance().notifyNetworkChange(false);
      }
    });
    return httpClient.build();
  }

  private boolean isNetworkAvailable(Context context) {
    ConnectivityManager cm =
        (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
    return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
  }
}

CompRoot is just a helper class. These things we can do with Dagger2. But In this tutorial, we are not using Dagger2 for decreasing the complexity of logic.

The code snippets we have put two major logic.
  • I’m creating RxBus named is ConnectionListener.
  • Create a subclass of ConnectionInterceptor

2.1. Create a singleton named is ConnectionListener

ConnectionListener is just a RxBus that written in Singletone design pattern. You see here we publishing notifyNetworkChange() and listen Observable in listenNetworkChange().

package com.example.internetconnection.network;

import io.reactivex.Observable;
import io.reactivex.subjects.BehaviorSubject;

public class ConnectionListener {
  private static ConnectionListener mInstance;

  public static ConnectionListener getInstance() {
    if (mInstance == null) {
      mInstance = new ConnectionListener();
    }
    return mInstance;
  }

  private ConnectionListener() {
  }

  //this how to create our bus
  private BehaviorSubject<Boolean> publisher = BehaviorSubject.create();

  public void notifyNetworkChange(Boolean isConnected) {
    publisher.onNext(isConnected);
  }

  // Listen should return an Observable
  public Observable<Boolean> listenNetworkChange() {
    return publisher;
  }
}

2.2 Write an abstract class which is a subclass of ConnectionInterceptor

This ConnectionInterceptor is intercepted every APIs call and check that time internet connection is available or not. based on that call appropriate methods

package com.example.internetconnection.network;

import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;

public abstract class ConnectionInterceptor implements Interceptor {

  public abstract boolean isInternetAvailable();

  public abstract void onInternetUnavailable();

  @Override
  public Response intercept(Chain chain) throws IOException {
    Request request = chain.request();
    if (!isInternetAvailable()) {
      onInternetUnavailable();
    }
    return chain.proceed(request);
  }
}

3. Write API interface method for Retrofit

This is the basic setup of APIs calling in Retrofit Android

package com.example.internetconnection.network;

import com.example.internetconnection.network.model.User;
import retrofit2.Call;
import retrofit2.http.GET;

public interface ApiService {

  @GET("users")
  Call<User> getUsers();
}

4. Build a superclass BaseActivity

Go to UI package and create a class named is BaseActivity which extends AppCompatActivity. Following things, we are doing in this class.

  • We initializing CompRoot and exposing methods name is getCompRoot()
  • On Activity onCreate() methods instantiate CompositeDisposable and depose on onDestroy()
  • In Activity onCreate() we are adding InternetConnectionListener
  • expose onInternetUnavailable() methods and call it on subscribe()
package com.example.internetconnection.ui;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.example.internetconnection.R;
import com.example.internetconnection.di.CompRoot;
import com.example.internetconnection.network.ConnectionListener;
import com.google.android.material.snackbar.Snackbar;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;

@SuppressLint("Registered")
public class BaseActivity extends AppCompatActivity {
  private CompRoot compRoot;
  private CompositeDisposable disposable;

  @Override protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    compRoot = new CompRoot();
    disposable = new CompositeDisposable();
    addInternetConnectionListener();
  }

  CompRoot getCompRoot() {
    return compRoot;
  }

  private void addInternetConnectionListener() {
    disposable.add(ConnectionListener.getInstance()
        .listenNetworkChange().subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Consumer<Boolean>() {
          @Override public void accept(Boolean aBoolean) throws Exception {
            onInternetUnavailable();
          }
        }));
  }

  @Override protected void onDestroy() {
    super.onDestroy();
    disposable.dispose();
  }

  protected void onInternetUnavailable() {
    showSnackBar(getString(R.string.no_internet_connection));
  }

  protected void showSnackBar(String message) {
    Snackbar.make(getView(), message, Snackbar.LENGTH_SHORT).show();
  }

  private View getView() {
    return findViewById(android.R.id.content);
  }
}

5. Open MainActivity and Paste below code

In this activity, we are simply calling APIs. and override onInternetUnavailable() for updating UI

package com.example.internetconnection.ui;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import com.example.internetconnection.R;
import com.example.internetconnection.network.ApiService;
import com.example.internetconnection.network.model.User;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class MainActivity extends BaseActivity {

  private static final String TAG = "MainActivity";

  ApiService apiService;
  TextView textView;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    // Bind Views
    textView = findViewById(R.id.textView);

    // Get ApiService service instance
    apiService = getCompRoot().getService();
    executeApiCall();
  }

  public void onRetry(View view) {
    executeApiCall();
  }

  private void executeApiCall() {
    apiService.getUsers().enqueue(new Callback<User>() {
      @Override public void onResponse(Call<User> call, Response<User> response) {
        Log.d(TAG, "onResponse: " + response.body());
      }

      @Override public void onFailure(Call<User> call, Throwable t) {
        Log.d(TAG, "onFailure: ");
      }
    });
  }

  @Override protected void onInternetUnavailable() {
    super.onInternetUnavailable();
    textView.setText(getString(R.string.no_internet_connection));
  }
}

Conclusion

That’s it! In this android tutorial, we have learned centralized network error handling Retrofit in Android. In previously we have to check internet connection before each APIs calls. Using this approach, you’ll able to manage all network call without writing any boilerplate code.

Retrofit globally error handling with RxJava

Leave a Reply

2000