1

I'm new to android and this is the first time trying to use MVP pattern in my code ... as I understand so far is that my view should talk to the presenter and the presenter to the model > then the presenter will talk again to view.. I wish I'm right with that !!! as shown below in my simple code example I'm trying to return a result value from the model to the presenter and then I will use this result value in the presenter to decide which method should I call in the view..I have 2 questions and I hope some helps. 1) The enqueue method is working async and the result value will always return empty or fail or whatever.. because it works alone... and when I try to use the execute method instead I'm facing a NetworkOnMainThreadException error... so how can I make the right way ? 2) Is this a right way in using MVP pattern ?

This is the SignupContract class

public class SignupContract {
public interface IView{
    void signupSuccess();
    void signupFailed(String message);
}

public interface IPresenter{
    void signup(UserProfile userProfile);
}

public interface IModel{
    String signup(UserProfile userProfile);
}

}
This is the View code..

public class SignupActivity extends AppCompatActivity implements SignupContract.IView {

//some code

@Override
protected void onCreate(Bundle savedInstanceState) {
    //some code

    createAccountBtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

           //some code

            presenter.signup(userProfile);
        }
    });
}

@Override
public void signupSuccess() {
    /*AppUtils.dismissLoadingDialog(SignupActivity.this,"","");*/
    Intent intent = new Intent(SignupActivity.this, SigninActivity.class);
    startActivity(intent);
    finish();
}

@Override
public void signupFailed(String message) {
    /*AppUtils.dismissLoadingDialog(SignupActivity.this,"","");*/
    AppUtils.showErrorMessage(SignupActivity.this, message);
}

and this is the presenter

public class SignupPresenter implements SignupContract.IPresenter {

SignupContract.IView view;
SignupContract.IModel model;

public SignupPresenter(SignupContract.IView view){
    model = new SignupModel();
    this.view = view;
}

@Override
public void signup(UserProfile userProfile) {

    userProfile = UserProfileCleaner.clean(userProfile, "signup");

    UserProfileDTO dto = new UserProfileDTO();
    String validationMessage = dto.validateUserProfile(userProfile, "signup");

    if(validationMessage != null && !validationMessage.equals("")){
        view.signupFailed(validationMessage);
    }else{


        String signupResult = model.signup(userProfile);

        if(signupResult.equals("success")){
            view.signupSuccess();
        }else {
            view.signupFailed(signupResult);
        }

    }

}

}

and this is the model class

public class SignupModel implements SignupContract.IModel {

private String TAG = "SignupModel";

private String result = "";

@Override
public String signup(UserProfile userProfile) {
    final Context context = DKApp.getContext();
    ServiceWrapper serviceWrapper = new ServiceWrapper(null);
    Call<SignupResponse> userSignUpCall = serviceWrapper.userSignUpCall(userProfile.getUser().getUsername(),
            userProfile.getUser().getPassword(),userProfile.getPhoneNumber(), userProfile.getEmailAddress(),
            userProfile.getFullName());


    userSignUpCall.enqueue(new Callback<SignupResponse>() {
        @Override
        public void onResponse(Call<SignupResponse> call, Response<SignupResponse> response) {
            if( response.body() != null && response.isSuccessful() ){
                Log.e(TAG,response.body().toString());
                if(response.body().getStatus() == 1){
                    //some code
                    result = "success";
                }else{
                    result = response.body().getMessage();
                }
            }else{
                result = context.getResources().getString(R.string.request_failed);
            }
        }

        @Override
        public void onFailure(Call<SignupResponse> call, Throwable t) {
            Log.e(TAG, "Failure : " + t.toString());
            result = context.getResources().getString(R.string.request_failed);
        }
    });

    return result;
}

}

ankuranurag2
  • 1,628
  • 11
  • 22

2 Answers2

0

You are making a asynchronous call in the model which may take 100ms or 2-4sec so getting signupResult from it like String signupResult = model.signup(userProfile);this is wrong.

Changes you will require :

1) Add onComplete method to IPresenter and change IModel

public interface IPresenter{ 
    void signup(UserProfile userProfile);
    //add
    void onComplete(String signUpresult);
} 

public interface IModel{ 
    //changed
    void signup(UserProfile userProfile);
} 

2) In your SignupPresenter pass the instance of presenter to model

public class SignupPresenter implements SignupContract.IPresenter { 
..

   public SignupPresenter(SignupContract.IView view){ 
       model = new SignupModel(this); 
       this.view = view;
   } 

   ...

   @Overrides
   public void onComplete(String signupResult){
      if(signupResult.equals("success")){
        view.signupSuccess(); 
      }else { 
         view.signupFailed(signupResult);
      }
   } 

   ...
}

3) In your SignupModel once the result is aquired call onComplete(//result) from the presenter

public class SignupModel implements SignupContract.IModel {

   SignupPresenter presenter; 

   public SignupModel(SignupPresenter presenter){ 
       this.presenter = presenter
   }

   @Override 
   public void signup(UserProfile userProfile) {
        ...
        userSignUpCall.enqueue(new Callback<SignupResponse>() {
        @Override 
        public void onResponse(Call<SignupResponse> call, Response<SignupResponse> response) { 
            if(response.body() != null && response.isSuccessful() ){ 

                if(response.body().getStatus() == 1){ 
                    //some code 
                    presenter.onComplete("success"); 
                }else{ 
                    presenter.onComplete(response.body().getMessage()); 
                } 
            }else{ 
                presenter.onComplete(context.getResources().getString(R.string.request_failed)); 
            } 
        } 

        @Override 
        public void onFailure(Call<SignupResponse> call, Throwable t) { 
            Log.e(TAG, "Failure : " + t.toString()); 
            presenter.onComplete(context.getResources().getString(R.string.request_failed));  
        } 
    }); 
   }

}

Needful : Show progress dialogue when signup is called and dismiss the same on onComplete in SignupPresenter.

Your understanding is quite good also know that the model should talk with presenter as well. To know more about MVP design pattern read this

Suyash Chavan
  • 681
  • 6
  • 18
  • 1
    what a greaaaat answer is this .... You JUST saved the world in a very simple and clear lines .. thank your very much Suyash Chavan – Mohammed Darwish Feb 07 '19 at 17:19
0

In MVP pattern you should make view dummy. Presenter always tells view what to do. Here is an example:

In View =>

presenter.login(userName, password)

In Presenter =>

fun login(userName: String, password: String) {
//login logic
     if(success) view.showLoginSuccess()
     else view.showLoginError()
}

This is a very short explanation of the MVP pattern. Regarding to your question you can not make requests on Main Thread. Luckily Retrofit has a thread management system. But you shouldn't use it in a model like this you can use it in presenter or search for clean architecture articles for the more right way. If you use it in presenter you should do something like

userSignUpCall.enqueue(new Callback<SignupResponse>() {
        @Override
        public void onResponse(Call<SignupResponse> call, Response<SignupResponse> response) {
            if( response.body() != null && response.isSuccessful() ){
                Log.e(TAG,response.body().toString());
                if(response.body().getStatus() == 1){
                    //some code
                    view.showMessage("success");
                }else{
                    view.showMessage(response.body().getMessage());
                }
            }else{
                view.showError(context.getResources().getString(R.string.request_failed));
            }
        }

        @Override
        public void onFailure(Call<SignupResponse> call, Throwable t) {
            Log.e(TAG, "Failure : " + t.toString());
            view.showError(context.getResources().getString(R.string.request_failed));
        }
    });
dtunctuncer
  • 268
  • 2
  • 14