Android

MVP architectural design pattern with reactive Rx in android

This article is a step-by-step introduction to MVP on Android, from a simplest possible example to best practices. The very first question comes in every developer is that what is MVP?

What is MVP: MVP stands for Model View Presenter. Let’s see what is meant of each aspect?

View: View is a layer that displays data and reacts to user actions. On Android, this could be an Activity, a Fragment, an android.view.View or a Dialog. View also represents the user interface component like Button, TextView etc. View displays the data from the model and also change the model from the user interface.

Model: Model is a data access layer such as database API or remote services API. A model represents the collection of classes that represent the business model and data model. It means that how the data can manipulate.

Presenter: Presenter is a layer that provides View with data from Model. The presenter also handles background tasks. It processes the view action of the user and makes the change into the model. Here there is the direct communication from model to view and vice Versa.

Why MVP: This is a very basic question that comes to everyone mind. Yes off course without knowing the reason why should I use this design as an architectural level in Android application developments. Ok, that’s fair enough, So the reason is very simple to start using MVP with. Ok, Let’s focus on two basic things.

  1. Keep the Design and Communication of each component is simple
  2. Managed Background Task and removed callback

Let’s discuss in detail this two reason that encourages us to start using MVP while building the Android app.

When We look above old design architecture, It seems like that every thing connected with every thing. A programmer is confused and involved in the fight with View complexities instead of solving business tasks.

OK Some how the diagram is not too complexed that’s Ok, But think again when view appears and disappears frequent and random and add few background tasks then manage to restore and store view. Then it will be very difficult to manage. A developer has only stuck to understand the view hierarchy complexity rather than focus on business logic which he wants to develop or implement.

After all the scenario the result comes that it is so complicated to resolve. Most of the part can not able to test and debug proper. Now let’s focus on MVP.

With MVP complex task has divided into multiple tasks. Let’s look at above diagram it is very clear that the only presenter is the mediator whose has responsible to communicate with view and data. No any direct communication with data to view. Here every module has a unique presenter to communicate for data to view or vice versa.

A developer can easily add the implementation and test the result easily. Overall the result will be Smaller objects, fewer bugs, easier to debug and Testable. View layer with MVP becomes so simple, so it does not even need to have callbacks when requesting for data. View logic becomes very linear.

Ok Let’s talk about the background task, In the old pattern, every activity or fragment or custom view has connected with a background task. Background task always running with multiple threads, for example, Async Task, it is running half part with a separate thread and remaining part with the main thread. In this case, chances will be the memory leak because some time process is killed because of memory low.

Or in other words, If a user flips the screen often this will cause memory leaks – every callback keeps a reference to MainActivity and will keep it in memory while a request is running. It is absolutely possible to get an application crash because of out-of-memory error or a significant application slowdown.

But in MVP all the background task and business logic will handle inside the presenter. It makes life easy because presenter only delivered the data to view when the view is alive or subscribed. The chances of memory leak will be very less. There are many reasons of memory leak, it generally happened with bad code practice. A developer should understand the good code practice. Here you can detail Why need to take care memory leak?

Let’s see the simple example of MVP.

First of all, we need to create the base contract to define the MVP. Here we need to create the two interface one for a presenter and other for a view.

public class BaseContract {

    public interface Presenter<T>{
        void subscribe();
        void unSubscribe();
        void attachView(T view);
    }

    public interface View {

    }
}

Now this base contract will be connected with each module. For example, I am defining the for KickStarterDetail Contract to show the detail of each item of recyclerview. here I want to show the data of this item from DB and show at a view.

public class KickStarterDetailContract {

    public interface Presenter extends BaseContract.Presenter<KickStarterDetailContract.View> {
        void loadDetailKickStarter(int s_no);
    }

    public interface View extends BaseContract.View{
        void onKickStartersOk(KickStarter kickStarter);
        void showLoadErrorMessage(String errorMsg);
        void showEmptyView(boolean isShow);

    }
}

Let’s create the Presenter to handle this request. All the business logic should be here. I mean in this example fetch data from DB and give it to view.

public class KickStarterDetailPresenter implements KickStarterDetailContract.Presenter{

    @NonNull
    private KickStarterDetailContract.View mKickStartView;
    private CompositeDisposable mCompositeDisposable;
    private  KickStarterLocalSource kickStarterLocalSource;


    public KickStarterDetailPresenter(){
        kickStarterLocalSource = new KickStarterLocalSource();
    }


    @Override
    public void subscribe() {
        if (mCompositeDisposable == null) {
            mCompositeDisposable = new CompositeDisposable();

        }
    }

    @Override
    public void unSubscribe() {
        mCompositeDisposable.clear();
    }

    @Override
    public void attachView(KickStarterDetailContract.View view) {
        mKickStartView = view;
    }

    @Override
    public void loadDetailKickStarter(int s_n0) {

        Log.v("", "S_SN: "+s_n0);
        Observable<KickStarter> kickStarterObservable = kickStarterLocalSource.getKickStarterById(s_n0);
        kickStarterObservable.doOnDispose(new Action() {
            @Override
            public void run() throws Exception {
              //  Toast.makeText(context, "Error", Toast.LENGTH_LONG).show();
            }
        }).subscribe(new Consumer<KickStarter>() {
            @Override
            public void accept(@io.reactivex.annotations.NonNull KickStarter kickStarter) throws Exception {
                mKickStartView.onKickStartersOk(kickStarter);
            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(@io.reactivex.annotations.NonNull Throwable throwable) throws Exception {
                mKickStartView.showLoadErrorMessage(throwable.getMessage());
            }
        }, new Action() {
            @Override
            public void run() throws Exception {
            }
        });

    }
}

In Fragment, it will take this data and show at the view. It is very simple and separates each and every thing. In the future, if it changes the business logic then I have to check the presenter class and modify it. It will not be so complex because I am not touching the view part.

public class KickStarterDetailFragment extends Fragment implements KickStarterDetailContract.View {

    public static final String Tag = KickStarterDetailFragment.class.getSimpleName();

    @BindView(R.id.appbar)
    AppBarLayout appbar;
    @BindView(R.id.pledgedvalue)
    TextView pledgedvalue;
    @BindView(R.id.backers_value)
    TextView backersValue;
    @BindView(R.id.relative)
    RelativeLayout relative;
    @BindView(R.id.main_content)
    CoordinatorLayout mainContent;
    @BindView(R.id.title)
    TextView titleText;
    @BindView(R.id.backers)
    TextView backers;
    @BindView(R.id.backdrop)
    ImageView backdrop;
    @BindView(R.id.toolbar)
    Toolbar toolbar;

    @BindView(R.id.blur)
    TextView blur;
    @BindView(R.id.perc)
    TextView perc;
    @BindView(R.id.collapsing_toolbar)
    CollapsingToolbarLayout collapsingToolbar;

    private String url;
    private String title;

    @Inject
    KickStarterDetailContract.Presenter mPresenter;

    public static KickStarterDetailFragment newInstance(int s_no) {
        KickStarterDetailFragment kickStarterDetailFragment = new KickStarterDetailFragment();
        Bundle bundle = new Bundle();
        bundle.putInt("s_no", s_no);
        kickStarterDetailFragment.setArguments(bundle);
        return kickStarterDetailFragment;
    }

    @Override
    public void onResume() {
        super.onResume();
        mPresenter.subscribe();
    }

    @Override
    public void onPause() {
        super.onPause();
        mPresenter.unSubscribe();
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        // do things if you want to create only first time when activity created.
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        injectDependency();
        mPresenter.attachView(this);
    }

    private void injectDependency() {
        ApplicationComponent applicationComponent = ((MainApplication) getActivity().getApplication()).getApplicationComponent();
        KickStarterDetailComponent kickStarterDetailComponent = DaggerKickStarterDetailComponent.builder()
                .applicationComponent(applicationComponent)
                .kickStarterDetailModule(new KickStarterDetailModule())
                .build();
        kickStarterDetailComponent.inject(this);
    }


    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View root = inflater.inflate(R.layout.fragment_kickstarter_detail, container, false);
        ButterKnife.bind(this, root);

        ((AppCompatActivity)getActivity()).setSupportActionBar(toolbar);
        ((AppCompatActivity)getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        collapsingToolbar.setTitle(title);

        Bundle bundle = this.getArguments();
        if (bundle != null) {
            int s_n0 = bundle.getInt("s_no");
            mPresenter.loadDetailKickStarter(s_n0);
        }

        return root;
    }

    @Override
    public void onKickStartersOk(KickStarter kickStarter) {
        url = kickStarter.getUrl();
        title = kickStarter.getTitle();
        pledgedvalue.setText(kickStarter.getAmt_pledged());
        backersValue.setText(kickStarter.getNum_backers());
        titleText.setText(title);
        blur.setText(kickStarter.getBlurb());
        perc.setText("Percentage: "+kickStarter.getPercentage()+ "%");
    }

    @Override
    public void showLoadErrorMessage(String errorMsg) {
        Toast.makeText(getActivity(), "Error "+ errorMsg, Toast.LENGTH_LONG).show();
    }

    @Override
    public void showEmptyView(boolean isShow) {

    }


    @Override
    public void onDestroyView() {
        super.onDestroyView();
    }
}

Here do not be confused I used a database of GreenDao ORM. If you need to get the detail of GreenDao then get the detail from here Exploring GreenDao database with reactive Rx.To understand the reactive Rx I would be recommended to check these posts of understanding of Java 8 stream and Rx Observables, and basic understanding and practice features and functions of RxJava, and understanding practice RxJava with RxBinding in Android.

I also used the dependency injection Dagger2 in above example. I would recommend to checking this post in Kotlin Dagger2 dependency injection.

Conclusion: 

MVP is the best architectural based design pattern. It provides the best code practice, easy to use and maintenance and easy for the JUnit testing and debug for a developer. Developers should always flow this sequence user -> view -> presenter -> model -> data sequence to avoid the complexity of code.  You can build an awesome Android application by using MVP design pattern with Reactive nature.  Here is the Github of full source code for practice more.

Please do subscribe email to get every newsletter of this blog and if you feel that this post will help you to better understand then do not forget to subscribe, share and comment below.

Happy coding 🙂

0 0 votes
Article Rating

Recent Posts

Hide your production API key or any sensitive data in Android

Hi everyone, In this article, we are going to learn how to hide the production… Read More

2 years ago

How to handle the localisation or multi language support in android with examples?

Hello everyone, Today in this article, we are going to learn about localisation to support… Read More

2 years ago

How to convert any callback to Coroutines and use them in Kotlin Android?

Hello everyone, In this article, we are going to learn something to handle the callback… Read More

2 years ago

Request Permission Launcher with Kotlin in Android

In this article, we are learning about the run time permissions for request permission launchers.… Read More

2 years ago

Implement the SMS User Consent API and SMS Retriever API in Android

Hello everyone. In my last tutorial, we learned about the Jetpack Compose introduction and about applying the… Read More

3 years ago

Jetpack Compose Coroutine flow with LiveData/ViewModel in Android

Hello everyone, In this article, we are going to learn about the Jetpack Compose with… Read More

3 years ago