RxJava and MVP in an Android app

I am trying to implement a screen in an Android application using MVP architecture and use RxJava and RxBinding on the View side.

Basically I have 2 Spinners, 1 TextEdit and a button that is disabled by default. I want to enable the button when Spinners has elements and the text box is not empty. Here is the code:

Observable.combineLatest( RxAdapterView.itemSelections(mFirstSpinner), RxAdapterView.itemSelections(mSecondSpinner), RxTextView.textChanges(mEditText), new Func3<Integer, Integer, CharSequence, Boolean>() { @Override public Boolean call(Integer first, Integer second, CharSequence value) { return !TextUtils.isEmpty(value); } }).subscribe(new Action1<Boolean>() { @Override public void call(Boolean enable) { mButton.setEnabled(enable); } }); 

Now the question is how to integrate this into the MVP pattern. Ideally, the "business logic" of turning on the button should be in the presenter. What is the best way to achieve this? Iโ€™m thinking about somehow transferring the initial observers to the presenter (how is the question?), And the presenter united these observers, and he would have the logic of turning on the button. In the end, it will simply call View to change the state of the button.

Are there any better options? Are there any good examples of MVP with RxJava on the View side?

+5
source share
2 answers

My suggestion:

You are on the right track. However, the RxBinding logic must still be in the view. I would move the logic around deciding whether to enable the button or not in the presenter.

Determine the value to save the model from all the fields you want to check:

 private class ViewValuesModel { public Integer adapter1Value; public Integer adapter2Value; public CharSequence textValue; public ViewValuesModel(Integer adapter1Value, Integer adapter2Value, CharSequence textValue) { this.adapter1Value = adapter1Value; this.adapter2Value = adapter2Value; this.textValue = textValue; } } 

Inside the view, create an Observable :

 Observable observable = Observable.combineLatest( RxAdapterView.itemSelections(mFirstSpinner), RxAdapterView.itemSelections(mSecondSpinner), RxTextView.textChanges(mEditText), new Func3<Integer, Integer, CharSequence, ViewValuesModel>() { @Override public ViewValuesModel call(Integer first, Integer second, CharSequence value) { return new ViewValuesModel(first, second, value); } } ) 

Then pass this Observable master:

 mPresenter.observeChoosableFieldChanges(observable). 

Inside the presenter, do the rest:

 observable .map(new Func1<ViewValuesModel, Boolean>() { @Override public Booleancall(ViewValuesModel viewStates) { return !TextUtils.isEmpty(viewStates.textValue); } }) .subscribe(new Action1<Boolean>() { @Override public void call(Boolean enable) { if (enable) { view.enableButton(); } } }); 
+5
source

You can list your sources and send events of the value of pairs to the object / processor, where you can make logic, enable or disable the button and send logical events. The guy who updates the button from the host will subscribe to this question / processor.

In this way, you have the flexibility to change sources and logic without changing the Presenter-View contract.

Essentially, you can have 2 absolutely decoupled components in Presenter:

1) that listens for incoming viewing events and creates a flow of actions to enable or disable the button 2) a component that listens to enable / disable actions and update the view accordingly (you can also achieve this using the Google Binding Library)

In this way, you can incorporate several decoupled interaction chains and, nevertheless, is easy to maintain due to the presence of triviality of components and the clarity of the flow connections.

You can also use smth, for example the RHub library . You can find component examples here.

0
source

Source: https://habr.com/ru/post/1258862/


All Articles