Clean Architecture – reactive approach

Clean Architecture – reactive approach
Clean Architecture can be approached in several ways. One solution is to use RxJava 2, and in this post we will take a close look at this approach.In the presentation layer we will use the proven standard Model View Presenter, in the domain layer we will have UseCases with a single responsibility, and in the data layer we will apply Repository Pattern. All of this will be controlled with RxJava streams.

Repository Pattern

Suppose that we have a presenter that gets us users and sets their data by calling the appropriate methods on the view. The presenter should not know where the data is from, therefore, first, let’s create UsersRepository, which will use the database and REST services.

In the following examples we also used Dagger2. It is not necessary, however it makes implementation much easier.

public class UsersRepository {

    public static final int DEFAULT_AMOUNT = 5;
    private UsersService usersService;
    private DatabaseManager databaseManager;

    public UsersRepository(UsersService usersService, DatabaseManager databaseManager) {
        this.usersService = usersService;
        this.databaseManager = databaseManager;

    public Flowable<User> loadUsers(String gender) {
        Flowable<User> remoteUsers = usersService.getUsersList(DEFAULT_AMOUNT).flatMap(Flowable::fromIterable);
        Flowable<User> localUsers = databaseManager.getUsers();
        return remoteUsers.concatWith(localUsers).filter(user -> user.getGender().equals(gender));

Let’s assume here that we are dealing with simplified logic, as if getting users from the repository provided the items from both the server and the database. We can do this by concatenating 2 streams from UsersService and DatabaseManager, objects injected to the repository using Dagger.

They both return the data using Flowable, however, the service provides us with a Flowable<List<User>>, and the database with Flowable<User>. Thanks to the operator fromIterable we process stream of a list to stream of items and concatenate both streams through concatWith. In addition, the method loadUsers accepts the argument of sex, which it uses to filter the users.

Use Case

We already have a finished repository, but the presenter should not use it directly. Into presenters we inject primarily UseCases, which can use multiple repositories. UseCases define all the actions that can be performed in the application and each of them has a single responsibility. So let’s create a GetUsersUseCase that gets users from the repository. Obviously, naming depends on convention, this is just the one I chose.

public class GetUsersUseCase extends SingleUseCase<List<User>> {

    private UsersRepository userRepository;
    private String gender;

    public GetUsersUseCase(UsersRepository userRepository) {
        this.userRepository = userRepository;

    public void setGender(String gender) {
        this.gender = gender;

    protected Single<List<User>> buildUseCaseSingle() {
        return userRepository.loadUsers(gender).toList();

As you can see, we can distinguish the method buildUseCaseSingle(), which we will override from the superior class – SingleUseCase. We will discuss its content in a moment, but for now the most important is that inside buildUseCaseSingle() method we return a stream that will be of interest to the presenter. In this case, it is a Single containing the list of users. If we want to call the method from the repository with selected parameters, we simply create an additional field and setter.

Single Use Case

public abstract class SingleUseCase<T> extends UseCase {

    protected abstract Single<T> buildUseCaseSingle();

    private Single<T> buildUseCaseSingleOnIo() {
        return buildUseCaseSingle().compose(RxUtil.applySingleIoSchedulers());

    public void execute(final Consumer<? super T> onSuccess) {
        disposable = buildUseCaseSingleOnIo().subscribe(onSuccess);

    public void execute(final Consumer<? super T> onSuccess, final Consumer<Throwable> onError) {
        disposable = buildUseCaseSingleOnIo().subscribe(onSuccess, onError);

SingleUseCase is a base UseCase returning Single of the chosen type. Single is simply a stream returning only one item, so after subscribing to it, we can handle onSuccess or onError. In this order we create the method execute in 2 versions: when we do not intend to handle the error (it is not advised to use), and for the case when we want to handle the error.

As the method buildUseCaseSingle() is abstract, and we have just implemented it in GetUsersUseCase, we should use it at this point. First, we set the appropriate Schedulers, here we are using compose and own method of util class. In short, it boils down to the use of operators subscribeOn( and observeOn(AndroidSchedulers.mainThread()), so that everything will be downloaded asynchronously in the background, and at the end we can use relevant data in the main thread.

public static <T> SingleTransformer<T, T> applySingleIoSchedulers() {
      return single -> single.subscribeOn(

Therefore in the execute methods we subscribe to already implemented method and assign the result to object disposable, which is located in the abstract base class UseCase:

public abstract class UseCase {

    protected Disposable disposable = Disposables.disposed();

    public void dispose() {

We do this in order to be able to stop the whole stream at any moment we need to. We can do it with the method dispose(), which the presenter will call on UseCase when it will be to be permanently destroyed or so. Similarly, we can also create FlowableUseCase or CompletableUseCase.


At the end it all comes down to injecting UseCase to the presenter and calling:

getUsersUseCase.execute(this::consumeUsers, this::handleError);

We implement methods consumeUsers and handleError in which we can work on the view. And when we destroy our view and disconnect the presenter permanently, we just need to call:


We can do this in many ways, for example after injecting a few UseCases to the presenter save them to the list and, if necessary, use:


I intentionally do not show the full implementation of the presenter, as there are many methods of doing MVP, and Clean Architecture can be used in virtually any of them. It is enough that the presenter uses appropriate UseCases.


I know that this is just an introduction, which is why I show the most important elements of architecture, so as not to hide the idea. Clean Architecture approach can be implemented in many ways, this is just one of them. Thanks to it, we can obtain a coherent, testable application architecture in a simple way.


Learn more

Static shortcuts in Android 7.1 Nougat

With the new Android version, Nougat 7.1 (API 25), Google gives us some interesting possibilities. One of them is the option to create shortcuts to an application. In this post I will show you how static shortcuts work.
Read more

Dagger 2 – about (sub)components in a few words

When getting into the subject of dependency injection, we need to understand numerous new techniques that enable us to control created objects. Dagger allows developers to declare interfaces that will handle that. We can create an interface which will be a component or a subcomponent. What is the difference?
Read more

ConstraintLayout, or not so fast, after all…

Recently, while browsing through news from Android world I came across a concept of ConstraintLayout. It is a new layout delivered by Android and Google, supporting Android versions from API 9 on. Digging into possibilities it is to give, I decided to check how new Layout Builder behaves and what is ConstraintLayout like in use.
Read more

Project estimation

Check out how we use our knowledge in practice, and make your project with us.

Why choose us?

Logo Mobile Trends Awards

Mobile Trends Awards 2017

Nomination in M-commerce category


clients reviews

Clutch logo
Logo Legalni bukmacherzy

Legal Bookmakers Award 2019

Best Mobile App


projects in portfolio