Recently I've been developing some functionality and it seems to me that it would be nicely modeled with some form of two-way binding.
Example: there's a screen where user can fill some forms and save some content. Later user can come back to that content and edit it. Content is stored in a DB so the content should be fetched asynchronously. I use RxJava and Mosby MVP to create MVVM-style connection between the fragment and presenter.
The problem is that forms should be validated on the fly, so any time some part of the View changes Presenter should be notified. But when asynchronous content from DB arrives (in case user is editing existing content) view can corrupt 'initial' state from DB because of the transition between the states. Also there's a risk of infinite event passing cycle between view and presenter (distinctUnitChanged() doesn't always help with this, because state can alter like 1-2-1-2-1)
I've found 2 workarounds but I am not satisfied with them because they're rather impure and don't feel like idiomatic FRP.
The first one is changing a view in the way that it doesn't send events until it received the first state from presenter.
The second one requires sacrificing Presenter purity. Presenting is setting a flag which tells if we should accept view's state change. It will skip events from view until it will receive the one it passed to the view (initial state).
Things are getting even harder because in Android view can disconnect and reconnect to the Presenter at any time (with or without saved state) and Presenter should be the source of truth.
If anyone has any examples of two-way binding implementation with RxJava or any ideas I would be grateful.
Consider using swichMap() (instead of flatMap()) when loading asynchronous content from DB as switchMap() unsubscribes from previous input validation while the user changes form.
Probably this solves your problem.
Btw. It seems that Mosby MVI module is better suited as traditional MVP for what you are trying to achieve (RxJava, Two-Way-Binding).
Related
Please does anyone have a link to a resource that helps in learning how to create an app using mvi design pattern but all code should be in Java and not Kotlin
Before you click! This is in Kotlin -> https://tech.olx.com/mvi-architecture-in-android-a-simple-livedata-based-approach-b4b23896fd32 But if you actually look at the code snippets there is not a single line that doesn't have an obvious Java counter part. There is not a single Kotlin exclusive item like Flow, Scoping, Coroutine anywhere.
You don't need to learn Kotlin to understand it, just read it.
The article explains MVI as a modified way to use a MVVM.
It has 2 (ViewState/ViewEffect) components that are observed by the view (Fragment/Activity)
It has 1 (ViewEvent) component that is used by the view to trigger changes in the observed components above.
ViewState : It contains your data, like a List, like a boolean that determines if something is enabled, etc...
When there is a change in any state data, like an update to the List, the observer receives everything, and updates everything.
ViewEffect : These are one off "effects" like starting an animation, making a toast. You will update this with new data when you not concerned about the state of the effect. Like I don't care if there is another toast on the screen, atm. Just make a new one with new information, and show it.
ViewEvent : This allows the ViewModel to receive events from the view and start the "update" process. If a button is clicked in the view all the view would do is send a ViewEvent to the ViewModel stating what has been clicked. Then the ViewModel updates the ViewState/ViewEffect based on the ViewEvent received, which then propagates to the view.
I've been reviewing the documents and I can't find anything talking about whether or not Litho supports data binding. There is one comment I've found here that says, "It supports one-directional data binding..." but there isn't anything in the docs that outlines how you might use data binding. So does Litho support data binding, if so, how do you use it?
Because Litho uses declarative approach to building UI, binding comes naturally – you just can't change a property on a View in-place, you need to recreate a new Component. So, when a new data comes from whatever source you have, you'll just recreate a Component and set it to LithoView or ComponentTree.
Another way is to pass your Controller as a Prop, subscribe to data changes and on every update of data, call a State Update for the Component, let's say. For subscribing/unsubscribing you can use OnAttached/OnDetached methods: https://fblitho.com/docs/onattached-ondetached
Let me know, if you need more info
I have been reading about MVVM pattern. View is supposed to observe for changes in ViewModel and act on it accordingly but I am confused if following code in View is ok in MVVM architecture.
fun onClick(view:View){
showUser(viewModel.getUserDisplayName())
}
Here View is not observing for a change, its rather asking for latest data from ViewModel. Is this considered correct in MVVM?
This is a question that possibly has no one answer, as different points might be made depending on the exact use case. However:
Sir Codesalot (great handle) is in my opinion technically correct. Let me elaborate.
In MVVM the view should pass UI interaction events (commands) to the ViewModel.
Here is an article from microsoft (who invented mvvm): https://msdn.microsoft.com/en-us/library/ff798384.aspx
The examples here are not related to android, but the concepts should be the same, especially if you look at the first diagram.
The ViewModel should do its magic, react to these events by manipulating data accordingly and then notify the observers (usually the view) of state changes. The view then reacts to the state changes.
In this way, if you would just pass data back from the ViewModel (in a synchronous way), then your view might be missing side effects. In your particular example, there probably aren't any, but consider that the method you call does not only return data, but also changes some internal state (e.g. counts the number of times the data was accessed). Then your view will not know of these.
Of course, you can make the case, that you can return all relevant data for the view, but it starts to break the single responsibility principle.
Here is an interesting blog post, which might give a better example, why the view should always get the state after the ViewModel: https://medium.com/upday-devs/mvvm-rxjava-learnings-1819423f9592
To the point of the other case, the wikipedia article about MVVM https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel states, that the ViewModel can expose public properties.
So in the end, it will most probably be cleaner if you do not return data directly. However, you are the architect and you know your app the best and there might be cases where patterns can be broken. After all they are guidelines. If you know why you break it (and maybe document it), then everything should work out.
For example, I have EditProjectFragment which contains few elements:
TextView (project name)
ColorPicker (project color)
Spinner (project type)
Let's see:
Project name will be restored by TextView itself
Who must store project's color?
Who must store spinner's value?
It seems to be ViewState's responsibility. For example, when user picks color, View calls presenter.onProjectColorPicked(color). Then, Presenter will call view.setProjectColor(color). Or View should update ViewState directly, without calling Presenter if it doesn't need?
Another example. User adds photo in EditNoteFragment. User picks photo(presenter.pickPhoto()) -> presenter.addPhoto(photo) called and notify View to add photo to ViewState&show it.
Should View update Note object by itself? Should it be done by Presenter? In the first case it means that ViewState will provide methods like getNote()/setNote(note) that will be used by View. Should I duplicate Note-reference via updating it in View.setNote(note) method? The second case means that I probably should store Note object in Presenter and just update View without passing Note in it. But it looks like a wrong way.
In other words: what View must do without Presenter's help(add a photo to Note object?) and what things with it(button clicks etc)?
Viewstate was meant to be used to represent different states from your View. I.e The view is displaying a loading indicator. so we could say that the view is in the "loading state". So whenever the "state" changes usually a presenter was involved because its the responsibility of the presenter to coordinate the views state. The question is: how do you define state? There is no silver bullet.
I don't think that it makes sense to play such a ping pong game like
presenter.onProjectColorPicked(color)
view.setProjectColor(color)
unless, you say that it goes down to the model (business logic) like this:
View calls presenter.onProjectColorPicked(color)
Presenter calls model.setColor(color)
model informs presenter (via observer pattern) that the model has been changed
Presenter calls view.setData(newModelWithChangedColor) containing the new color
In general: the view is just displaying (via presenter) what the current state of the "model" is.
ViewState is just a little helper to deal with screen orientation changes and process death in a slightly more convenient way (compared to traditional onSaveInstanceState(Bundle) implementations).
So ask yourself: What is the state of your "model". Usually, the view's state is the same as the state of the "model".
In the first example, it seems that it is an issue of color picker and spinner to not save the the picked things internally. Therefore, doing that manually in onSaveInstanceState() for the picker / spinner is the default way the android team recommends to go. So, if you just want to use the ViewState feature to not use onSaveInstanceState() because you find it more convenient to use ViewState then this is fine too, although it is not exactly what ViewState was meant for.
After some thinking/reading (especially following series) I came to accept the following general rules for implementing MVC:
Model - set of simple dummy Value Objects, responsible for keeping the state. Model classes are Observable and notify Observers - i.e. views when changed. Model code could be android agnostic.
View - classes able to keep/update its visual state - based on android.view.View/ViewGroup family - by inheritance or composition. View classes are Model-aware, they receive update of Model's state and re-draw accordingly. All user-input listening code is delegated to Controller.
Controller - all user-input processing code in your activity/fragments. Controller updates the Model, which in turn, will trigger subscribed View update.
Sounds simple and certainly doable in most cases.
Now, consider for example:
Controller/Activity keeps track of 2 Model objects model1 and model2 and changes them based on some application logic.
View receives updates from objects model1 and model2 independently as per design above.
Now, suppose the View wants to show animation based on mutual transition of both model1 and model2 for which it needs to know changes of both objects at one time, or as a single event.
What would be recommended way of doing it, keeping mvc design above in place?
I thought about options:
Have a "SmartModel" which encapsulates both model1 and model2, make the mutual changes/transition and inform the View. I don't like this approach because Model becomes not really just "dumb" state representation, but also drags some application logic from Controller.
Have Controller inform the View about the changes it did on both model1 and model2. In that case neither model1 nor model2 need to implement ability to notify the View, i.e. there is no link between Model->View anymore.
May be there is much better option / I am missing something.
Any insightful suggestions will be highly appreciated.
I think the option 2) is similiar with MVP pattern, controller is kind of presenter to change the view for model.
Model View Controller, Model View Presenter, and Model View ViewModel Design Patterns
If you want to follow the strict MVC way, maybe you need to fire some change event to notify the View observers, so they can know what and how exactly the model changes, so they can do partial refresh and animation.