3
votes

I was implementing MVP in my new application, then I came across a problem. I needed to call a method of View, inside View (Activity) itself. It is by definition of MVP code separation, wrong thing to do.

By definition:

The Presenter is in charge of the the orchestration between the Model and the View. It basically receive events from both and act consequently. The Presenter is the only component that knows others. It has a reference to the View and a another to the Model. (source)

In the same article it was mentioned that View does not reacts to user interactions, it passes control to Presenter to do the job. I have also read this SOF post about dependency rules.

In my case, I am using custom AppTheme. AppTheme needs to be set before setContent() call, what I am doing is create a method in View interface called setAppTheme() which my Activity implements, and there is code to apply theme. Now the problem is, this is called within the app, which makes calling of a View method inside its implementation.

To sum up, what my understanding of MVP either one of the following should be true:

  • Do call View method inside Activity, because setTheme() wont work after setContent() and our presenter.setView() is in onResume(), but will this satisfy MVP separation of M-V-P ?

  • Do not make interface method for setAppTheme(), instead create a private method in Activity which sets theme. This method will have nothing to do with any layer of MVP. But question is, if project is using MVP pattern, is this practice valid?

Here is my MVP:

public class AboutUsMVP
{

    public interface Model
    {


        String getFbLink();
        String getTwitterLink();
        String getEmailLink();
        String getCompanyLink();

    }

    public interface Presenter
    {
        void setView( View view );

        void fbButtonClicked();

        void twitterButtonClicked();

        void emailButtonClicked();

        void imageButtonClicked();

    }

    public interface View
    {

        void showFacebookPage();
        void showTwitterPage();
        void showEmailIntent();
        void showCompanyWebsite();
        void setAppTheme();
        void setCustomActionBar();

    }

}

Please do point out mistakes where I missed them.

From what I know, same case can be argued in the light of setActionBar() and setOnClickListener() methods, although these may require their separate post, but they are more relevant here and new post for either of them will be duplicate.

Please note that my Activity implements View interface.

EDIT: More explanation

My View is actually Activity class. This is View of MVP, not Android API's View class. The thing is, there is a method setAppTheme() which only related to View of MVP, (Activity of Android). This call is not in the Contract (AboutUsMVP.java) which by Google convention should be AboutUsContract.java, this setAppTheme() is not in Contract, and it cant be, so does this violate MVP principle?

There is no possible alternative, one can say make an interface of setAppTheme(), if I do so, it will not work because:

setAppTheme() is called just after super() method, if not it is useless. And MVP's presenter starts working in onResume. If an interface is made, and setAppTheme() is brought into MVP's jurisdiction, it will have no effect.

2
Is your theme dynamic and based on user's interactions? Otherwise why not to set the theme directly in the Manifest? I'm quite new with MVP too but I think it's correct to call the Presenter to init the View (your setView()) in onCreate, then the Presenter calls setAppTheme. Just after presenter.setView() you can call setContentView as normal.Eselfar
Yes, user can change theme while app is running, and it will be saved in consistent storage.Talha
If you looking in kotlin then go here github.com/saveendhiman/SampleAppKotlinSaveen
Will have a look at it.Talha

2 Answers

3
votes

Indeed, Views in an MVP are supposed to be dumb. This is: they don't contain any logic. Just receive the event generated by the user and immediately delegate its work to the presenter. The View can also inform the presenter that some events have happened (the view has been created, the screen rotate, etc)

This can lead to some confusions. Who is responsible of calling some methods? As you said the View has to perform some actions like setOnClickListener but the presenter is responsible of handling the event. Just have this in mind:

The View is just an interface. This means that you can use anything that implements that interface

Right now you're making a mobile app. But if you wanted to code a console or a desktop app, the presentation logic doesn't change. Anything that is specific to the "View technology" (android, desktop, etc) should be performed inside the code specific to that technology. This way your code will be loosely coupled to your tech stack

1
votes

I believe @Pelocho answer is correct and you should mark it as the right one. But I would like to present my answer (that agrees with his) but from an alternative point-of-view. On for this different POV I would like to debate your on definition of presenter:

The Presenter is in charge of the the orchestration between the Model and the View

So the question I propose here is: "what is this model that the presenter interacts with?". And my answer to it is to look into the classic "note-taking" application and argue that the model is text and associated meta-data, usually stored in some DB that the presenter will read, parse and push to the view.

Nowhere in this "model" the application theme is relevant. Theme is purely a function of the view. Theme is only associated to the final on-screen looks of it. Just like the view is the one in charge of layouting the content on screen, or to know what font size to use.

And that means even if those layouting, size, colors can be changed from a user settings option, it still falls outside the responsibility of the presenter and the model, as they're only interested in the content.

tl;dr:

Just read the theme on the Activity.onCreate (before super.onCreate) directly from the SharedPreferences and do not involve the Presenter on it.