Mobile Development 14 min read

Mastering Android MVP Architecture with RxJava: A Step‑by‑Step Guide

This article explains how to choose an Android framework, build a layered MVP architecture, and use RxJava to move network requests off the main thread, providing clear code examples and practical tips for scalable, testable mobile apps.

Tencent TDS Service
Tencent TDS Service
Tencent TDS Service
Mastering Android MVP Architecture with RxJava: A Step‑by‑Step Guide

1. Choosing an Android Development Framework

Native Android development starts with a simple MVC pattern, which works for small projects but becomes hard to read, maintain, and test as the app grows. When complexity reaches a certain level, a more flexible architecture is needed to improve readability, maintainability, and testability.

Only when project complexity reaches a threshold do you need a more flexible framework; a simple Hello World does not require any third‑party framework.

The goal of any framework is to enhance code readability , maintainability and testability . If you use a framework just for the sake of it, you will likely suffer.

Two core ideas solve these problems: layering and modularization . Layering decouples vertically, while modularization decouples horizontally.

Common decoupling methods are layering and modularization .

Horizontal modularization groups related features into the same directory, and can be extended with plug‑ins for more complex separation. Vertical layering varies by project, and more layers appear as complexity grows.

In a classic Android MVC project, business logic quickly inflates the Activity, making the code hard to read and maintain. Therefore, the Android‑official MVP pattern is introduced to split the project into distinct layers.

2. Building a Layered Framework Step by Step

Reference articles such as "Android Application Architecture" and "Android Architecture Blueprints" can be consulted, but this guide shows a concise MVP implementation.

The following diagram (from the references) shows a simple MVC structure where Activity directly interacts with the data layer via apiProvider or CacheProvider:

When the activity handles both UI and data fetching, it quickly becomes bloated. MVP introduces two new layers: Presenter and DataManager , separating view logic from business logic.

Below is the core code implementation.

public class MainActivity extends Activity implements MainView {
    MainPresenter presenter;
    TextView mShowTxt;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mShowTxt = (TextView) findViewById(R.id.text1);
        loadDatas();
    }
    public void loadDatas() {
        presenter = new MainPresenter();
        presenter.addTaskListener(this);
        presenter.getString();
    }
    @Override
    public void onShowString(String str) {
        mShowTxt.setText(str);
    }
}

The view interface:

public interface MainView {
    void onShowString(String json);
}

The presenter connects view and model:

public class MainPresenter {
    MainView mainView;
    TaskManager taskData;
    public MainPresenter() {
        this.taskData = new TaskManager(new TaskDataSourceImpl());
    }
    public MainPresenter test() {
        this.taskData = new TaskManager(new TaskDataSourceTestImpl());
        return this;
    }
    public MainPresenter addTaskListener(MainView viewListener) {
        this.mainView = viewListener;
        return this;
    }
    public void getString() {
        String str = taskData.getTaskName();
        mainView.onShowString(str);
    }
}

The data layer interface and implementations:

public interface TaskDataSource {
    String getStringFromRemote();
    String getStringFromCache();
}
public class TaskDataSourceImpl implements TaskDataSource {
    @Override
    public String getStringFromRemote() { return "Hello "; }
    @Override
    public String getStringFromCache() { return "World"; }
}
public class TaskDataSourceTestImpl implements TaskDataSource {
    @Override
    public String getStringFromRemote() { return "Hello "; }
    @Override
    public String getStringFromCache() { return " world Test "; }
}

The business layer TaskManager receives a TaskDataSource and combines data without caring about its origin, making it easy to test by injecting different implementations.

public class TaskManager {
    TaskDataSource dataSource;
    public TaskManager(TaskDataSource dataSource) { this.dataSource = dataSource; }
    public String getShowContent() {
        // Combine remote and cache data
        return dataSource.getStringFromRemote() + dataSource.getStringFromCache();
    }
}
The advantage of using interfaces is that each layer communicates through a contract, allowing different implementations for production and testing.

Network operations cannot be performed on the main thread; Android throws NetworkOnMainThreadException . The naive solution of creating a new thread for each request leads to boilerplate and hard‑to‑read code.

RxJava provides a concise, reactive way to move IO work off the UI thread.

3. Using RxJava to Solve Main‑Thread Network Requests

Add the following dependencies:

compile 'io.reactivex:rxjava:1.0.14'
compile 'io.reactivex:rxandroid:1.0.1'

Modify the presenter to use RxJava:

public void getString() {
    Func1<String, String> dataAction = new Func1<String, String>() {
        @Override
        public String call(String param) {
            return taskData.getTaskName();
        }
    };
    Action1<String> viewAction = new Action1<String>() {
        @Override
        public void call(String str) {
            mainView.onShowString(str);
        }
    };
    Observable.just("")
        .observeOn(Schedulers.io())
        .map(dataAction)
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(viewAction);
}

RxJava schedules the data fetching on an IO thread and delivers the result back on the Android main thread, keeping UI code clean and avoiding nested callbacks.

When the application grows, RxJava’s chainable operators make it easy to add caching, parallel requests, dependent calls, debounce UI clicks, reactive UI updates, and complex data transformations.

4. Conclusion

By combining MVP with RxJava, we obtain a flexible Android architecture consisting of four layers: View, Presenter, Business (Model), and Data. The main benefits are:

Each layer is independent and communicates via interfaces.

Different implementations can be swapped for production or testing.

All business logic runs off the UI thread, minimizing UI lag.

RxJava enables concise, chainable asynchronous calls, eliminating callback hell.

While this approach solves many problems, it may still have drawbacks; feedback is welcome.
architectureAndroidRxJavaMVPlayered design
Tencent TDS Service
Written by

Tencent TDS Service

TDS Service offers client and web front‑end developers and operators an intelligent low‑code platform, cross‑platform development framework, universal release platform, runtime container engine, monitoring and analysis platform, and a security‑privacy compliance suite.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.