In MVP is onClick responsibility of View or Presenter?
Asked Answered
G

2

23

In the MVP pattern who is responsible to handle clicks on the UI?
E.g. the non-MVP approach would be something like:

counterButton.setOnClickListener(new View.OnClickListener() {
    public void onClick(View v) {
      totalClicks++;
      counterTextView.setText("Total clicks so far: "+totalClicks);
    }
  });

Using MVP is the onClick the responsibility of the Presenter? Or the View can handle that?
Can someone please clarify this?

Gahan answered 13/7, 2016 at 19:48 Comment(0)
R
34

OnClick should call a Presenter method. You should do your business in presenter and if you need to update the ui you should define a method in your View and call it from presenter.

You need a method for your View ex:

public void showCounterCount(final int totalClicks){
     counterTextView.setText("Total clicks so far: "+totalClicks);
}

Also you need a method and a variable in your Presenter:

int totalClicks = 0;

public void onCounterButtonClicked(){
    totalClicks++;
    mView.showCounterCount(totalClicks);
}

And refactor your code like this:

counterButton.setOnClickListener(new View.OnClickListener() {
    public void onClick(View v) {
      mPresenter.onCounterButtonClicked();
    }
  });

For more complex and clean architecture you can do your use case business in interactors. (In your example incrementing a counter value is a use-case for your application)

You can define an interactor and increment your counter value there.

CounterInteractor:

public CounterInteractor{
   public int incrementCounter(int currentCounter){
       return currentCounter+1;
   }
}

And refactor your presenter like below:

int totalClicks = 0;
CounterInteractor mCounterInteractor = new CounterInteractor();

public void onCounterButtonClicked(){
    totalClicks = mCounterInteractor.incrementCounter(totalClicks);
    mView.showCounterCount(totalClicks);
}

With this approach you separate your business logic totally from presenters and re use your use-case concepts without duplicating code in presenters. This is more clean approach.

You can also check this git repo for different MVP Approaches. https://github.com/googlesamples/android-architecture/tree/todo-mvp-clean/

Good luck.

Edit:

Here's my lightweight wikipedia client project source: https://github.com/savepopulation/wikilight

I'm trying to implement MVP. (MVP + Dagger2 + RxJava)

Rhea answered 13/7, 2016 at 20:9 Comment(6)
To be honest, if that is the MVP approach, I don't really see it as an improvement than the original snippet. We just added 1 abstraction/redirection but where is the benefit?Gahan
we divide app to three layers and separate business logic from ui. activities and fragments are views and only responsible for updating ui and just contains interface methods which get called by presenter. your example is very simple so it's hard to see the benefits but in large apps you can see it more clearly. also it's useful for ui testing. you can check this link. antonioleiva.com/mvp-androidRhea
A major benefit is testing. In the above example you can write a unit test for the onCounterButtonClicked() method in the Presenter without any dependency on the Android framework. Such tests can run on the JVM. As an aside I avoid words such as button and click in my Presenter method names to less tightly link them to the concepts of the View layerDenominative
and what happen if I have 4 buttons , should I implement something like mPresenter.onclick(buttonView) or something like if (ButtonView.getId() == logingButon.getId(){mPresenter.onloginclick}else if (.......)Conflux
@JeCuRo hi sorry for my late answer. i think if your buttons do completely different operations you should implement 4 different presenter methods and call them from views. passing an android view component to presenter (button etc.) is not suitable for mvp because your presenters must be independent from android sdk for testing.Rhea
hi @Rhea got it , never is late. Thanks a lotConflux
G
4

In MVP, it is the responsibility of the View to know how to capture the click, not to decide what to do on it. As soon as the View captures the click, it must call the relevant method in the Presenter to act upon it:

------------------- View --------------------

button1.setOnClickListener(new OnClickListener({
presenter.doWhenButton1isClicked();
}));

------------------ Presenter ----------------

public void doWhenButton1isClicked(){
// do whatever business requires
}

I have a series of articles on architectural patterns in android, part 3 of which is about MVP. You might find it helpful.

Guarani answered 21/4, 2018 at 12:39 Comment(4)
What if it is an item in recyclerview instead of a button. Is it correct to pass reference of view to the presenter such as presenter.onCardViewClick(cardView); ? Also how to handle new Intent when a cardView is clicked?Acclivity
@Adi, No, you don't need to pass the view element to the presenter. Anything that is finally done on any view element shall be done by the View, so why should the presenter has access to it? So, in your case, you should call "presenter.onCardViewClick()" (without the argument). For New intent, you pass the onclick to the presenter, as above, and then presenter calls a method in the view, such as "view.goToNewActivity()" in which new intent is handled. So the way you do the intent is handled in a method inside the View.Guarani
In my case, for a new intent, i need to extract the userId from the cardview to show the user profile. Basically, click on a card view does not have same outcome. The bare minimum i need to do i believe is presenter.onCardViewClick(String userId). However, this feels like putting business logic inside view. What is your thought?Acclivity
@Adi, passing userId or any other data from view to presenter to do whatever business demands on that is the correct way and is different from doing business logic in the viewlayer. For example, if you wanted to fetched user profile by userId in the view this would have been putting the logic inside the view. However, you are not doing any business logic by passing userId to presenter. Instead, the presenter is responsible for whatever it needs to do on this data.Guarani

© 2022 - 2024 — McMap. All rights reserved.