starkej2
starkej2

Reputation: 11529

Android MVP - passing string resources from the presenter to the view

I've recently started developing an Android app with a model–view–presenter architecture. One issue that keeps coming up that I haven't been able to find a good solution for is passing strings from the presenter to be displayed in the view.

I am trying to keep Android system dependencies out of the presenter layer to make unit testing easier. This is simple when providing a string that comes from a server or some other external source. When I need to display a simple error message that is always the same, I can just have a method like showWhateverError(), where the view already knows which string resource to use and can handle loading the resource itself. And when I have business logic that determines which string resource to provide the view, I can just reference the string resource ID in the presenter (although that feels wrong too).

The case that I haven't come up with a good solution for is when I need to display a string that sometimes comes from the server and is sometimes a string resource, based on some business logic. Any ideas would be helpful!

Upvotes: 2

Views: 2672

Answers (2)

Jahnold
Jahnold

Reputation: 7683

For these situations I have additional helper class which I call a Formatter. I pass the current state from my Presenter to the View which then asks the Formatter for the appropriate strings based on that state. I think a small example will help:

You have an object which represents the data you wish to set on the View. Let's call it State for now:

public class State {

    private final boolean isServerString;
    private final String serverString;

    public State(boolean isServerString, String serverString) {
        this.isServerString = isServerString;
        this.serverString = serverString;
    }

    public boolean isServerString() {
        return isServerString;
    }

    public String getServerString() {
        return serverString;
    }
}

In you Presenter you would create this based on whatever logic you need and pass it to the View:

public class MessagePresenter {

    private void setMessage() {

        // logic here

        State state = new State(true, "Hello from the server");
        view().setMessage(state);
    }
}

Then in your Activity/Fragment/ViewGroup you'd have something along the lines of:

public class MyActivity extends Activity implements MessageView {

    private MessageFormatter formatter;
    private TextView messageTextView;

    @Override
    public setMessage(State state) {

        String message = formatter.getMessage(state);
        messageTextView.setText(message);
    }
}

As you can see the view asks the Formatter for the String to display in the TextView. The Formatter would look something like this:

public class MessageFormatter {

    private Context context;

    public MessageFormatter(Context context) {
        this.context = context;
    }

    public String getMessage(State state) {

        return state.isServerString()
                ? state.getServerString()
                : context.getString(R.string.default_message);
    }
}

It takes a Context as a constructor param and, yes it does have a little bit of logic in it. However the heavy lifting logic remains in the Presenter. Most of the time it should just be a simple boolean check.

The real power of using this method comes into play when you make a Formatter interface and then use your Presenter to decide which Formatter to instantiate. As an example you can then create a HoliidayMessageFormatter and a DefaultMessageFormatter which would allow you to give you app a different theme based on a small logic check in the Presenter.

Upvotes: 3

Mohsen Mirhoseini
Mohsen Mirhoseini

Reputation: 8882

The error message visualisation must be handled using View!

Your presenter have to call the related error method, for instance invalidEmail(), and the view have to decide how to interact with user and use UI elements to show the error.

In some implementations you may want to show an animation instead of a message! therefore sending the message from down layers to view is not right.

Here is a sample repo which can help you with learning more about MVP, Dagger, Testing and other concepts:

http://github.com/mmirhoseini/marvel

I hope it help :)

Upvotes: 1

Related Questions