oldergod / android-architecture

MVI architecture Implementation of the ToDo app.
Apache License 2.0
669 stars 70 forks source link

Filtering intents by state? #15

Closed saik0 closed 6 years ago

saik0 commented 6 years ago

I'm implementing an MVI that draws alot of inspiration form here, great work.

In my application some actions can only be performed from certain states. (Example: The user should only be able to submit a form that has passed validation, and cant submit when a request is in flight)

I'm thinking the cleanest approach is to filter the intent stream, and log/throw/ignore when the intent cant be transformed into an action for the current state.

However, the state resides in the state reducer, it is not accessible to the intent transformer. I'm not sure how to implement the desired behavior, and would greatly appreciate your feedback.

oldergod commented 6 years ago

How about adding that info inside the state?

Like you could have

class State {
  // you validate your form inside the ViewModel or somewhere. (Out of the UI)
  boolean isFormValid;
  // Depends on your code but basically,
  // you would want to be able to know if a request is in flight.
  RequestStatus requestStatus;
}

then inside your UI, you would just reflect based on the state.

class MyActivity {
  void render(State state) {
    if (state.isFormValid || requestStatus != IN_FLIGHT) {
      submitButton.enabled = true
    } else {
      submitButton.enabled = false
    }
  }
}
saik0 commented 6 years ago

Yes. This was my thought as well, however:

saik0 commented 6 years ago

Whoops hit the close and comment button. Haha.

oldergod commented 6 years ago

The View is not ensuring anything. It only renders the screen based on a state, and listens to the user. The fact that you can or cannot hit a button is a state that the UI only reflects onto the screen.

If you only change threads inside the processors, the data flow itself is on the main thread so that's unlikely. If you want to be sure only one click can happen per frame, you can use something like ButterKnife's DebouncingOnClickListener.java.

You could have a flag then somewhere and do something like RxView(submitButton).clicks().filter(ignored -> canSubmit).map( ignored -> SubmitIntent())