2
votes

I am trying to create substructure with Dagger2 and eveything works fine.

My main problem is starting when I need invoke presenter methods in my model file. Let me give more detail.

As you can seen in my Model file I request to server with retrofit and based on the result I should invoke a method from presenter. Because Model will decide which method should be worked in presenter and according to choosed method the presenter will invoke view methods. But problem is that the Presenter is using the Model by calling in Constructor but even the Presenter is a middle man, Model can not use the Presenter.

  1. This substructure below is right for MVP.
  2. Whos duty to request server Presenter or Model?
  3. If my substructure is right, how should Model invoke the presenter files with Dagger2?

It is my MVP interface cluster.

public interface IRegisterMVP {

    interface View extends IGeneralViewOps{

        void showWarning( String warningMessage );

        void openMainActivity();
    }

    interface Presenter {

        void setView( View view );

        void registerTriggered( ArrayMap< String, String > userParameters );

        void registerTriggered( EditText userName, EditText mailAddress, EditText password, EditText passwordRepeat );

        void notValidated( String warningMessage );

        void validate();
    }

    interface Model {

        void validateData( ArrayMap< String, String > userParameters );

    }

It is my Module

@Module
public class UserOperationsModule {

    @Provides
    public IRegisterMVP.Presenter provideRegisterPresenter( IRegisterMVP.Model model ){
        return new RegisterFragmentPresenter( model );

    }

    @Provides
    public IRegisterMVP.Model provideRegisterModel( Context context, IRegisterMVP.Presenter presenter ){
        return new UserBussinessModel( context );

    }

}

It is my Presenter

public class RegisterFragmentPresenter implements IRegisterMVP.Presenter {

private IRegisterMVP.View mView;
private IRegisterMVP.Model mModel;

public RegisterFragmentPresenter( IRegisterMVP.Model mModel ) {
    this.mModel = mModel;
}

@Override
public void setView( IRegisterMVP.View view ) {
    this.mView = view;

}

@Override
public void registerTriggered( ArrayMap< String, String > userParameters ) {
    this.mModel.validateData( userParameters );

}

@Override
public void registerTriggered( EditText userName, EditText mailAddress, EditText password, EditText passwordRepeat ) {

    ArrayMap< String, String > createViewValues = new ArrayMap<>( 4 );
    createViewValues.put( UserBussinessModel.USER_NAME, userName.getText().toString() );
    createViewValues.put( UserBussinessModel.USER_MAIL_ADDRES, mailAddress.getText().toString() );
    createViewValues.put( UserBussinessModel.USER_PASS, password.getText().toString() );
    createViewValues.put( UserBussinessModel.USER_PASS_REPEAT, passwordRepeat.getText().toString() );

    this.registerTriggered( createViewValues );
}

@Override
public void notValidated( String warningMessage ) {
    this.mView.hideWaitingView();
    this.mView.showWarning( warningMessage );

}

@Override
public void validate() {
    this.mView.hideWaitingView();
    this.mView.openMainActivity();

}

}

And it is my businessmodel file

public UserBussinessModel( Context context ) {
    this.mContext = context;

}

public UserBussinessModel( Context mContext, IRegisterMVP.Presenter mRegisterPresenter ) {
    this.mContext = mContext;
    this.mRegisterPresenter = mRegisterPresenter;
}

public UserBussinessModel( Context mContext, LoginMVP.Presenter mLoginPresenter ) {
    this.mContext = mContext;
    this.mLoginPresenter = mLoginPresenter;
}

@Override
public void validateData( ArrayMap< String, String > userParameters ) {
  Call< MainModel< Fortune > > jsonObjectCall =    this.mFortuneService.getSpesificFortuneBasedOnUser( userUUID, fortune_id );
    jsonObjectCall.enqueue( new Callback< MainModel< Fortune > >() {
        @Override
        public void onResponse( Call< MainModel< Fortune > > call, Response< MainModel< Fortune > > response ) {
        // HOW SHOULD MODEL INVOKE THE PRESENTER METHOD IN ORDER TO ARRANGE VIEW FILES?
        }

        @Override
        public void onFailure( Call< MainModel< Fortune > > call, Throwable t ) {
         // HOW SHOULD MODEL INVOKE THE PRESENTER METHOD IN ORDER TO ARRANGE VIEW FILES?
        }
    } );
}
1

1 Answers

1
votes

If you are interested in implementing MVP in Android, please refer to the Google Android Architecture Blueprints.

With respect to your question:

Because Model will decide which method should be worked in presenter and according to choosed method the presenter will invoke view methods.

This isn't the usual way of doing MVP. In MVP, the model is passive and the presenter is the agent.

model view presenter

(Diagram from MVP Wikipedia page)

As per the diagram above, the presenter manipulates the model, and the model doesn't know or care about the presenter. When it is necessary for the model to notify the presenter of state change events it is done through the presenter registering for callbacks from the model. This is also clear in the Blueprint example:

@Inject
TasksPresenter(TasksRepository tasksRepository, TasksContract.View tasksView) {
    mTasksRepository = tasksRepository;
    mTasksView = tasksView;
}

The presenter takes a dependency on the model (the tasks repository) but the tasks repository doesn't know or care about who is consuming it. While the linked example doesn't show a state-change event propagating from the model layer to the presenter, if there was one it probably be done through registering a callback inside the presenter layer. Something like the following:

mTasksRepository.registerStateChangeEvent(this);

Likewise, the example also shows loading similar to yours and correctly places this inside the presenter:

private void loadStatistics() {
    mStatisticsView.setProgressIndicator(true);

    // The network request might be handled in a different thread so make sure Espresso knows
    // that the app is busy until the response is handled.
    EspressoIdlingResource.increment(); // App is busy until further notice

    mTasksRepository.getTasks(new TasksDataSource.LoadTasksCallback() {
    //snip    

Because mTasksRepository doesn't take any dependencies that relate to the view or presenter and is manipulated as a patient by the presenter, we still maintain separation of concerns.