Retrofit

Retrofit is a type-safe HTTP client for android and java provided by Square. Retrofit handle all the type of network call like Post, Get, Put etc. We can upload or download a file using multipart easily using retrofit.

RxJava

RxJava is a Reactive Extensions for the JVM. RxJava can be used for composing asynchronous and event-based programs using observable sequences for the Java VM.

The main basic building block of Rxjava is Observable and Subscriber. Observable is the source of an event which emits data and Subscriber subscribes to observable and consumes data.

RxAndroid

RxAndroid provides android specific bindings for RxJava. it provides a Scheduler that schedules on the main thread or any given Looper. 

 

Integration

Let’s Start How to call network API’s using Retrofit 2 with RxJava 2.

First, we need to add the required dependencies in our gradle file.

dependencies {
 
    compile 'com.android.support:appcompat-v7:25.3.1'
    compile 'com.android.support:recyclerview-v7:25.3.1'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
 
    // RxJava and RxAndroid dependency identifier
    compile 'io.reactivex.rxjava2:rxjava:2.1.0'
    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
 
    // Retrofit dependency identifier
    compile 'com.squareup.retrofit2:retrofit:2.3.0'
 
    // Retrofit gson converter for serialization and deserialization of objects
    // Retrofit also provide many converter for Jackson, Moshi, Protobuf etc.
    compile 'com.squareup.retrofit2:converter-gson:2.3.0'
 
    // Retrofit rxjava2 adapter it allows you to return an Observable, 
    // Flowable, Single, Completable or Maybe from service methods.
    compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
 
    compile 'com.squareup.okhttp3:logging-interceptor:3.8.0'
 
    compile 'com.squareup.picasso:picasso:2.5.2'
}

Adding Permission to AndroidManifest.xml file

// for internet access
<uses-permission android:name="android.permission.INTERNET" />
 
// for knowing network state like internet is available or not
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Creating an OkHttpClientHelper.java class

OkHttpClientHelper class initializes OkHttpClient by setting cache size, cache directory, connection timeout time and adds logging interceptor for debugging HTTP call.

class OkHttpClientHelper {

    private static final int DISK_CACHE_SIZE = 50 * 1024 * 1024; // 50MB

    private OkHttpClientHelper() {
    }

    @NonNull
    static OkHttpClient provideOkHttpClient(Context context, boolean debug) {
        // Install an HTTP cache in the context cache directory.
        File cacheDir = new File(context.getCacheDir(), "http_cache");
        Cache cache = new Cache(cacheDir, DISK_CACHE_SIZE);

        OkHttpClient.Builder builder = new OkHttpClient.Builder().cache(cache);
        builder.connectTimeout(5, TimeUnit.MINUTES).readTimeout(5, TimeUnit.MINUTES);

        if (debug) {
            HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
            loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
            builder.addInterceptor(loggingInterceptor);
        }
        return builder.build();
    }

    static OkHttpClient provideOkHttpClient(Context context) {
        return provideOkHttpClient(context, false);
    }
}

Creating an ApiHelper.java class

ApiHelper class initializes the Retrofit object by adding base URL of API, OkHttpClient is used to send HTTP request and read the response, Gson converter factory for serialization and deserialization, and RxJava2CallAdapterFactory used for returning an Observable, Flowable, Single, Completable or Maybe from service methods.

In this example, I have used GitHub API for fetching user list.

public class ApiHelper {

    private static final String BASE_URL = "https://api.github.com/";
    private OkHttpClient okHttpClient;

    private ApiHelper(Context context) {
        okHttpClient = OkHttpClientHelper.provideOkHttpClient(context);
    }

    public static ApiHelper getInstance(Context context) {
        return new ApiHelper(context);
    }

    private Retrofit provideRestAdapter() {
        return new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .client(okHttpClient)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
    }

    public <S> S getService(Class<S> serviceClass) {
        return provideRestAdapter().create(serviceClass);
    }
}

Creating a GitHubUserService.java interface

Retrofit turns your HTTP API into a Java interface. GitHubUserService defines API call for getting user list.

public interface GitHubUserService {
    @GET("users")
    Observable<JsonArray> getGitHubUser();
}

Create layout item_layout_git_hub_user.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:app="http://schemas.android.com/apk/res-auto"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:paddingBottom="12dp"
 android:paddingTop="12dp">

 <android.support.constraint.Guideline
 android:id="@+id/guideLine"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:orientation="vertical"
 app:layout_constraintEnd_toEndOf="parent"
 app:layout_constraintGuide_percent="0.2"
 app:layout_constraintStart_toStartOf="parent" />

 <ImageView
 android:id="@+id/ivAvatar"
 android:layout_width="0dp"
 android:layout_height="40dp"
 android:adjustViewBounds="true"
 android:src="@drawable/ic_github_logo"
 app:layout_constraintEnd_toEndOf="@id/guideLine"
 app:layout_constraintStart_toStartOf="parent" />

 <TextView
 android:id="@+id/tvUserName"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="User Name"
 android:textSize="18sp"
 app:layout_constraintBottom_toBottomOf="parent"
 app:layout_constraintEnd_toEndOf="parent"
 app:layout_constraintHorizontal_bias="0.0"
 app:layout_constraintStart_toStartOf="@id/guideLine"
 app:layout_constraintTop_toTopOf="parent"
 tools:layout_editor_absoluteX="64dp" />


</android.support.constraint.ConstraintLayout>

Create GitHubUserAdapter.java class

GitHubUserAdapter binds the dataset to git hub user list item view.

public class GitHubUserAdapter extends RecyclerView.Adapter<GitHubUserAdapter.ViewHolder> {

    private Context mContext;
    private List<GitHubUser> mGitHubUserList = new ArrayList<>();
    private OnItemClickListener mOnItemClickListener;

    public GitHubUserAdapter(Context context) {
        mContext = context;
    }

    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
        this.mOnItemClickListener = onItemClickListener;
    }

    public void setData(List<GitHubUser> gitHubUserList) {
        mGitHubUserList = gitHubUserList;
        notifyDataSetChanged();
    }

    public void addAll(List<GitHubUser> gitHubUserList) {
        int pos = mGitHubUserList.size();
        mGitHubUserList.addAll(gitHubUserList);
        notifyItemRangeInserted(pos, gitHubUserList.size());
    }

    public void add(GitHubUser gitHubUser) {
        int pos = mGitHubUserList.size();
        mGitHubUserList.add(gitHubUser);
        notifyItemInserted(pos);
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout_git_hub_user, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        GitHubUser gitHubUser = mGitHubUserList.get(position);

        holder.tvUserName.setText(gitHubUser.getLogin());
        if (!TextUtils.isEmpty(gitHubUser.getAvatarUrl())) {
            Picasso.with(mContext)
                    .load(gitHubUser.getAvatarUrl())
                    .placeholder(R.drawable.ic_github_logo)
                    .error(R.drawable.ic_github_logo)
                    .into(holder.ivAvatar);
        }
    }

    @Override
    public int getItemCount() {
        return mGitHubUserList.size();
    }

    @Override
    public void onViewDetachedFromWindow(ViewHolder holder) {
        super.onViewDetachedFromWindow(holder);
        holder.cleanup();
    }

    public interface OnItemClickListener {
        void onItemClick(View v, GitHubUser gitHubUser, int position);
    }

    class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

        private ImageView ivAvatar;
        private TextView tvUserName;


        public ViewHolder(View itemView) {
            super(itemView);
            ivAvatar = (ImageView) itemView.findViewById(R.id.ivAvatar);
            tvUserName = (TextView) itemView.findViewById(R.id.tvUserName);
            itemView.setOnClickListener(this);
        }

        @Override
        public void onClick(View v) {
            if (mOnItemClickListener != null) {
                mOnItemClickListener.onItemClick(v, mGitHubUserList.get(getAdapterPosition()), getAdapterPosition());
            }
        }

        public void cleanup() {
            Picasso.with(ivAvatar.getContext())
                    .cancelRequest(ivAvatar);
            ivAvatar.setImageDrawable(null);
        }
    }
}

Add RecyclerView in activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.ln.rxjavawithretrofit.activity.MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</android.support.constraint.ConstraintLayout>

 

Initialize RecyclerView, setAdapter and call API to get the list of GitHub users and set into RecyclerView.

public class MainActivity extends AppCompatActivity {

    private static final String TAG = MainActivity.class.getSimpleName();
    private RecyclerView mRecyclerView;
    private GitHubUserAdapter mGitHubUserAdapter;
    private CompositeDisposable mCompositeDisposable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mCompositeDisposable = new CompositeDisposable();
        initView();
        callApi();
    }

    /**
     * initialize views
     */
    private void initView() {
        mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        mGitHubUserAdapter = new GitHubUserAdapter(this);
        mRecyclerView.setAdapter(mGitHubUserAdapter);
    }

    private void callApi() {
        // check network is available or not if available then call api
        // otherwise show alert dialog
        if (!NetworkUtils.isInternetAvailable(this)) {
            NetworkUtils.showNetworkAlertDialog(this);
            return;
        }

        // observable object prepared and returned from getService method of api helper class
        // getGitHubUser method return observable object
        Observable<JsonArray> observable = ApiHelper
                .getInstance(this)
                .getService(GitHubUserService.class)
                .getGitHubUser();

        Disposable disposable = RxJava2ApiCallHelper.call(observable, new RxJava2ApiCallback<JsonArray>() {
            @Override
            public void onSuccess(JsonArray jsonArray) {
                Log.d(TAG, "onSuccess() called with: jsonArray = [" + jsonArray + "]");
                if (jsonArray != null) {
                    ArrayList<GitHubUser> gitHubUserArrayList = new ArrayList<>();
                    for (JsonElement jsonElement : jsonArray) {
                        GitHubUser gitHubUsers = new Gson().fromJson(jsonElement, GitHubUser.class);
                        gitHubUserArrayList.add(gitHubUsers);
                    }
                    mGitHubUserAdapter.setData(gitHubUserArrayList);
                }
            }

            @Override
            public void onFailed(Throwable throwable) {
                Log.d(TAG, "onFailed() called with: throwable = [" + throwable + "]");
            }
        });

        mCompositeDisposable.add(disposable);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mCompositeDisposable != null) {
            mCompositeDisposable.dispose();
        }
    }
}

In MainActivity.java class,

CompositeDisposable

CompositeDisposable is a container that can hold multiple disposable. When activity is destroyed, we can cancel all the initiated API calls by calling dispose() method of the CompositeDisposable object.

RxJava2ApiCallHelper

RxJava2ApiCallHelper contains call method that calls API and provides a callback to the caller by RxJava2ApiCallback. Below is the implementation of both the classes.

RxJava2ApiCallHelper.java

public class RxJava2ApiCallHelper {

    public static <T> Disposable call(Observable<T> observable, final RxJava2ApiCallback<T> rxApiCallback) {

        if (observable == null) {
            throw new IllegalArgumentException("Observable must not be null.");
        }

        if (rxApiCallback == null) {
            throw new IllegalArgumentException("Callback must not be null.");
        }

        return observable
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<T>() {
                    @Override
                    public void accept(@NonNull T t) throws Exception {
                        // success response
                        rxApiCallback.onSuccess(t);
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(@NonNull Throwable throwable) throws Exception {
                        // failure response
                        if (throwable != null) {
                            rxApiCallback.onFailed(throwable);
                        } else {
                            rxApiCallback.onFailed(new Throwable("Something went wrong"));
                        }
                    }
                });
    }
}

call() method has two parameters namely observable and callback for returning Disposable so that we can add it into CompositeDisposable and when activity is destroyed, we can cancel all the initiated API calls.

RxJava2ApiCallback.java interface

public interface RxJava2ApiCallback<T> {
    void onSuccess(T t);

    void onFailed(Throwable throwable);
}

RxJava2ApiCallback interface is used as a parameter for calling API. RxJava2ApiCallback has two methods namely onSuccess and onFailed. If the API is executed successfully, then onSuccess callback method is called from RxJava2ApiCallHelper class otherwise onFailed callback method is called.

The complete example source code is available on github repository.

 

 

Want to work with us? We're hiring!