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.
Final Outcome
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.
Get Solution Code
Retrofit globally error handling with RxJava