sockeqwe / mosby

A Model-View-Presenter / Model-View-Intent library for modern Android apps
http://hannesdorfmann.com/mosby/
Apache License 2.0
5.49k stars 841 forks source link

MVI bind intents dynamically #207

Closed TobiasRe closed 7 years ago

TobiasRe commented 7 years ago

Hi Hannes, thanks for your awesome work on introducing the MVI pattern to the Android world. I'm currently evaluating this pattern for upcoming projects.

During my tests I'm seeing the need of binding view intents dynamically after the creation of the presenter. Eg.: An activity changes it's state based on user interaction and an additional widget (EditText) will be inflated. The needs EditText needs it's own intent for the user interaction. How is this intent created, since the presenter of the activity binds the intents on creation, before the new EditText is instantiated?

sockeqwe commented 7 years ago

Hi, with Mosby you can assume that all UI Widgets are available before the presenter is instantiated (I have to take some time to make that more clear in the documentation).

for example, in Activity.onCreate() you call setContentView(R.layout.my_layout) and then you can use findViewById() etc. to get references to your UI widgets. Mosby guarantees that presenter is created after Activity.onCreate() (presenter will be created in Activity.onStart())

The same is true for Fragments: Mosby guarantees that presenter is instantiated after Fragment.onCreateView() and ViewGroups.

Nevertheless, if you create your UI dynamically and you create UI widgets after Presenter is instantiated it is not a problem at all because all that must exist before the Presenter is instantiated is the Observable that represents the intent and NOT your dynamically created UI widget per se.

So for instance you could use Subject i.e. PublishSubject like this:

class MyActivity extends MviActivity<MyView, MyState> implements MyView {

      private PublishSubject<String> searchIntentSubject = PublishSubject.create();

       ...
       @Override  // Defined in MyView interface
       public Observable<String> searchIntent() {
            return searchIntentSubject;
       }

       ...
      @Override 
      public void onResume() {
          super.onResume();
          // This is called after presenter is instantiated and intents are bound
          EditText editText = new EditText(this);
          editText.addTextChangedListener(new TextWatcher() {

             public void onTextChanged(String s) {
                 searchIntentSubject.onNext(s);
             }
             ... 
         }
          containerLayout.add(editText);
      }
}

Hope that helps.

TobiasRe commented 7 years ago

Thank you. The PublishSubject approach is a very good idea! This will solve my issue.

sockeqwe commented 7 years ago

You may find https://github.com/JakeWharton/RxRelay useful (just in case that you haven't seen it before)

TobiasRe commented 7 years ago

This is even better, since there won't be errors emitted in this subject. The RxJava world is quite overwhelming in the beginning