MVP — How to present different errors on View Layer using only one method?

Written by mohsenoid | Published 2016/12/15
Tech Story Tags: android | android-app-development | mvp | error-handling

TLDRvia the TL;DR App

Using MVP we are always busy with interfaces to transfer different messages from presenter layer to view layer and presenting them to the user, But when it comes to error handling, are all these methods required and likely to get fired or even predictable?

What is the problem exactly?

  • showErrorOnOffline()
  • showErrorOnServiceNotResponding()
  • showErrorOnUnableToParseResult()
  • showErrorOnNoResponse()
  • and we know that there could be more…

We want to show errors to the user, so we add some methods for every error to their View’s interface and call them by Presenter, but how many errors are going to be handled? The dilemma also shows up when we are about to generalize some general methods inside a BaseView interface which all views extend that one.

Recently I have come up with a new idea which is worth to share with the community and get some feedback on…

Talk is cheap; show me the code

I use to generalize my interfaces and extend them from some Base interfaces which contain whatever everyone needs:

public interface BaseView {

void showMessage(String message);  

void showOfflineMessage(boolean isCritical);  

void **showErrorMessage**(Throwable throwable);  

void showProgress();  

void hideProgress();

}

and in my child View interface I extend it like:

public interface TopUpView extends BaseView {

void showBankGateway(String url);

void **showBankGatewayError**();

void setVoucherResult(int amount, String voucher);

void **showVoucherError**();

}

But wait a minute ! Isn’t it more convenient to handle errors with one single method, shared between all sub-interfaces?

In this example, I removed all error methods in TopUpView and try to use the one in BaseView (i.e. showErrorMessage)

First of all, I have to mention that usually, these errors happen in onError implementation of RxJava which usually comes from an API call using retrofit:

if (isConnected) {subscription = interactor.applyVoucher(voucher, amount).subscribe(calculateResponse ->{if (null != view)view.hideProgress();

                /\* ... \*/  
        },  
        throwable -> {  
            if (null != view) {  
                view.hideProgress();  

                if (isConnected)  
                    **view.showVoucherError();**  
                else  
                    view.showOfflineMessage(false);  
            }  
        };  

} else {if (null != view)view.showOfflineMessage(false);}

As I mentioned, there is a general showErrorMessage() method which has been never called, leaving out the SOLID principle:

Interface segregation principle: “many client-specific interfaces are better than one general-purpose interface.”

, and here comes a better solution…

I’m a fan of Java and since errors in Java are propagated using Exceptions, why not use them in the MVP layers communications?

Let’s create some custom exception classes for errors that might happen:

public class VoucherException extends Exception {

public **VoucherException**(Throwable throwable) {  
    super(throwable);  
}  

}

Bear in mind that you can encapsulate more fields, if that’s the case and then pass them to the view:

throwable -> {if (null != view) {view.hideProgress();

if (isConnected)  
    view.showErrorMessage(new **VoucherException**(throwable));  
else  
    view.showOfflineMessage(false);  
}  

};

This is how the BaseView’s showErrorMessage() handles the error occurrence and other View interfaces become more cleaner:

public interface TopUpView extends BaseView {

void showBankGateway(String url);

void setVoucherResult(int amount, String voucher);

}

, and we present errors inside our Activity or Fragment according to exception we received:

@Overridepublic void showErrorMessage(Throwable throwable) {Timber.e(throwable, "Error!");

if (throwable _instanceof_ **VoucherException**)  
    showToastMessage(getString(R.string._error\_voucher_));  
else if (throwable _instanceof_ **TopUpException**)  
    showToastMessage(getString(R.string._error\_application_));  

}

The last but not the least, we don’t need to hard-code any more error messages in the Presenter layer!!! This is how View layer shows relevant error messages from resources (R file) to user!

TL;DR

I have used exceptions to handle errors using one showErrorMessage method inside my BaseView interface and try to clean my code by removing duplicate error methods.

UPDATE:

According to some responses to this article and more researches about MVP, this solution is fine but it is not the best practice and you have to take care of all exceptions happening inside Presenter using a separate method in the View layer.

Thanks for reading this. I am always busy with improving and cleaning my codes, so please leave a comment if you are okay with this solution and will use it inside your project? and if not why?

Share this article if you think it is useful, and follow me for more articles Mohsen Mirhoseini Argi.

Mohsen Mirhoseini - Senior Android Developer_I am a senior Android Developer with about nine years experience in the field of Computer Software engineering. I have…_mirhoseini.info


Written by mohsenoid | Senior Android Developer
Published by HackerNoon on 2016/12/15