developing app, I thought whether my viewModel.setTitle(text) is an anti patter or not.
I know the Ideal of a viewmodel is that doesn't know anything about the views.
But the View know the viewmodel.
So I tried that var title = MutableLiveData<String> in viewmodel, and the view set the title text like this viewModel.setTitle(text)
I want to know my using viewmodel.setTitle is an anti pattern or nothing.
I think it will be a great understanding for you. If you're setting on a string on `observable it'll not breaking the pattern. Here is the detailed discussion regarding this topic
So according to my knowledge, lets consider the responsibilities of each layer first
View - Observes data in ViewModel and notifies UI event
ViewModel - Presentation logic
Model - Business logic
So view should be notifying the ui events to ViewModel, in your case view is actually asking the ViewModel to set the title.
So I have a suggestion, are you getting the title from an Intent, if yes then why not pass the bundle directly to ViewModel and let the ViewModel parse the data
viewModel.onCreate(bundle)
Since onCreate is an UI event we can use it in viewModel as well.
In your viewModel.onCreate your ViewModel can set title, fetch some initial data and do what is require to initialise the activity/fragment
If you are getting the title from server/backend i.e dynamic title, than I think your ViewModel can directly handle it
If your title is static and is set directly, then you should ask yourself is there a good reason to pass the title to your viewModel and set it from there, does it benefits you or is just creating boilerplate. If you are using it from strings.xml you can change it directly from strings file
So to answer your question is it an anti pattern, according to me yes. Why? instead of notifying UI event to viewModel, view is actually passing data to viewModel
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 created a library here: https://github.com/chanjungkim/ALiveData
This library is made because of MutableLiveData<ArrayList<T>>. Many people who learns about LiveData complains or they are confused with this type when they need to manipulate(add, remove, etc) the MutableLiveData. That's because ArrayList is easy to manipulate and _arrayList.value!!.add(item) or _arrayList.value!!.remove(0) seems to notify. But they don't.
At the end, when we want to notify, we must assign a value like _arrayList.value!! = mList. ArrayList and List both need to set the data like _arrayList.value!! = mArrayList or _arrayList.value!! = mList.
My question is List doesn't have add(), remove(), etc. On the other hand, ArrayList already has those functions and helps us manipulate the list much easier.
some people suggested like this
_list.value = list.value.toMutableList().doWhatever().toList()
So, what's the point of using List over ArrayList? Could you give me example with the explanation of using it?
LiveData can be used in different ways, and of course there is no one correct way, but a very common way of using it is within the Android MVVM architecture recommended by Google for use in Android apps.
In this architecture, the Activity (or Fragment) observe the LiveData of the ViewModel. When doing this, the goal would be to make the UI as 'dumb' as possible, where you try to handle as much of the app logic and behaviour in the ViewModel, and the Activity simply observes and reflects it on the UI.
In a case like this, it is often preferable for the values of the LiveData being observed to be immutable.
By doing this, it limits the Activity from being able to manipulate the data it is observing, such as add()ing or remove()ing anything from it. As just described, the goal should be to limit the UI's ability to make exactly these type of changes. If the Activity wants to add() an item to an ArrayList that it is observing, it should instead do this by calling a method on the ViewModel, which will in turn update it's own LiveData.value to the new, updated list, which will in turn be observed by the Activity and updated on the UI.
By only allowing the Activity to observe the immutable values, it helps enforce this separation of concerns, and limits any accidental 'leak' of logic into the Activity itself.
This idea can be extended further by ensuring that the observed values are of type LiveData, and not MutableLiveData. Using the latter can allow the Activity to manipulate the live data on its own, and break the MVVM pattern.
A List is an interface, and defines the methods that must be implemented by any classes that would like to behave like a list. It can be considered the 'most basic' version of a list, and only defines the minimum requirements for an implementing class to behave like a list.
In the same way, the List interface itself extends the Collections interface, which in turn extends the Iterable interface. Each one adds more functionality to the one before it... kind of like lego blocks stacked on top of each other, creating more complex shapes.
An ArrayList is a class, which implements MutableList (which itself implements List). This means that an ArrayList can be instantiated, and passed around as an actual object. Because of this object oriented design, and according to the Liskov substitution principle, any class (or interface) can be replaced by a subclass (or class implementing the interface) interchangeably.
This is a fundamental principle to object oriented design. It helps break parts of the application down into smaller, more basic and more manageable pieces, and then grow as required.
To answer your question more specifically, if the class that is observing the LiveData only cares about the methods defined in the List interface, then that is the all it requires to know about the value. The actual value could in fact be an ArrayList, a MutableList or even a custom class MyOwnFancyList<E>: List<E>, it does not matter to the observer, just as long as it implements the List interface.
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.
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).
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.