I understand that the advantage of the MVI pattern is that it is a single-state flow. So is it really necessary to have only one state model in MVI?
My app has several activities, and the subject of data obtained for each activity is completely different. For example, activity A gets the dog's information, and activity B gets the information of a Github user. In this case, if MVI-pattern should be only one state model, the mvi state model contains all the data information of activities A and B?
In most cases we're talking about single-state per ViewModel. And ViewModel is (usually, but not always) bound to a single screen. There is absolutely no incentive to store whole application state in a single object, that would get out of hand really quick
Adding to the accepted answer, Mvi is one of the presentation patterns, which addresses and try to solve the presentation problems. so by presentation we mean Single Screen whether it's an Activity, Fragment or Ui controller.
So with screen A, you'll have uni directional flow to get the Dog's information, and another one to Screen B, and so on.
Related
In the MVVM architecture, where does one start an activity for result ? For example, I need to get banking informations from an nfc tag in my payment app. What I do is I start the ReadNFCActivity from my PaymentActivity, retrieve the results there, and then I call my PaymentViewModel's updatePaymentInformations(name: String, account_number: Int...) method from my PaymentActivity. The data going from one activity to the other before being sent to the viewModel doesn't feel like the right way. How would you structure this ?
Any help will be appreciated !
In MVVV you shouldn't gather or keep data in your views. In your example you shouldn't get data from the card in the view. You can get the data from the card in the viewmodel and save in a Livedata variable. Whenever you need to display the data you can observe this Livedata. Handling the data this way can help you in complicate lifecycle aware data management scenarios.
Its better to think of Activities as containing a view not the view itself. Meaning showing stuff on the screen is not it's only purpose it is also a/the context of the app which allows access to OS functionality and resources.
Unlike Windows where you can access OS functionality and resources anywhere making MVVM trivial, instead in Android you have to access it through a context, which is the Activity/Application.
IMO
If your activity is starting another activity for a result than its well with its right to do that, because its the context. Passing that result to the view model is no different than sending input from a listener to the view model like text input.
If the view model isn't touch the views than you view model is good to go.
I'm working on application which uses Jetpack Compose with Jetpack Compose Navigation. In one view (destination) I'm displaying list on entries (let's call it View A with Model A). From this view user can go to creation view (View B with Model B), where new entry can be created. After successfull creation, I want to update list in Model A, so user don't need to refresh View A after going back to see newly created entry.
Is it possible to pass ViewModel class between navigation destinations using NavHost like this or in any other way?
As per the Thinking in Compose guide:
your composables are responsible for transforming the current application state into a UI every time the observable data updates.
That application state is the source of truth. This matches the Guide to app architecture, where your state is owned by lower level components that are responsible for the actual fetching, storing and caching of data, which is then exposed to the UI layer. This layer responsible for fetching, storing, and caching data is often called the 'repository layer'.
That means that directly passing snapshots of data between destinations in your navigation graph is exactly the wrong way to approach the problem: it creates a source of truth problem (do you trust the snapshot you sent between destinations or the repository?). The answer is always the same: your repository should always be the source of truth and you should never be passing snapshots of data between destinations. In this way, every screen that uses the repository as its source of truth automatically has the most up to date information and there is never a need to 'refresh' your data.
So your architecture would include three layers:
A single repository that owns your list of entries. The most simple part of this may just be the list held in memory as a mutableStateOf<List<Entry>>() that you update when the data changes with a new list. This class would be responsible for talking to the server, caching locally, etc.
(optionally, and a best practice) a layer of ViewModels, one for Screen A and one for Screen B that expose only the sets of methods from the repository specifically needed for that screen (i.e., your ViewModel A might expose a getEntries(), while ViewModel B might expose a createEntry(Entry) method.
Screen A and B focus solely on displaying the data retrieved from their associated ViewModel. As both are talking to the same repository layer, Screen B creating an entry will update the list that Screen A will retrieve its data from.
I am working on a small application using MVP pattern. My home activity has viewpager with multiple fragments in it and each fragment has its own presenter. Fragments aren't communicating with each other so the activity doesn't have any logic, it is just initializing fragments on start.
So if I would like to implement the pattern by the book and stay true to its principals should I implement presenter also for the activity? And if so what should be its role?
If you want to implement MVP by the book and stay true to its principals, every UI that has user interaction should have a presenter. In this case, if your activity is not interacting with the user, there is no need to have a presenter, and your fragments can have their own. If your activity needs, let's say show a loading to the user because of some data loading prior to show the fragments (this is a user interaction because you are interacting with the user to let them know that something is happening so they should wait), then might be good to consider having a presenter for the activity.
MVP doesn't care at all about whether is an Activity/Fragment/View, it just knows View which is considered as an abstraction of whatever can be shown to the user :)
That is at least, from the 'rules' perspective. My 2 cents is, be flexible, if you see that it actually ends up adding value to you and your project, do it, otherwise, sometimes you have to 'break' the rules or create your own.
For using the fragments with their own presenters, I try to use the presenter-contract classes duo to manage the UI events in the fragments.
For example, Consider a click event to show a toast message in case of two possible outcomes: 1. Save and 2. Delete
Then, I will declare two view contract methods like this:
interface View{
fun showSaveMessage()
fun showDeleteMessage()
}
And then, in the fragment, I will use an instance of my presenter class to display the messages at appropriate times like: presenter.doSaveAction(), the presenter in turn will cause the view to show the toast message.
Also, when I come to the actual logic of the fragment, like for fetching some data from a remote server, I use Interactor class along with the Presenter-View classes to perform it.
I believe staying true to all the principles is virtually dependent on what kind of application you are building. Sometimes, it is more feasible to use MVVM with MVP than only MVP pattern for the app architecture too.
I hope this answers your question, kind of?
Is there a difference between the "newer" Model-View-Intent architecture compared to the "older" ones like MVC and MVVM?
What issue does MVI address? What are the similarities with MVC/MVVM? What are the differences?
There are similar questions already on stackoverflow for MVC/MVV/MVP but none so far that explains MVI.
What is the difference between MVC and MVVM?
What are MVP and MVC and what is the difference?
from my experience each architecture pattern of those was invented to solve specific problem that the previous one ignored or wasn't observed yet.
MVC - Model View Controller
in UI applications the responsibilty of rendering the data to the screen, or the business logic and bind those together at first wasn't clear. so MVC came to define those responsibility to three components, each one has one purpose, and the picture describe the relation between those three components.
View - is the UI component that has all the properties like color, shape, tools to listen to the click events .. etc.
Model - is the component that define the business logic that you want the view to render and behave accordingly.
Controller - is the one who change the model, so if the view has a name for example to save, View pass it to the controller then controller manipulate the model with the right actions.
MVP - Model view presenter
the problem with MVC that there is a great coupling between the three components, if you want to change the view calls, it will require you to update controller and the Model.
and that's clear from the MVC picture, the relationship between the three components is very tied, you couldn't replace one of those components without the other.
So MVP came to provide a more clean solution to the previous problem by separating the Model and the View, keep the interactions between them via the Presenter, Presenter is the middle man that each the view and the model call.
So if you want to save a list of favorites movies, View listen to user (*) action, then call the presenter function that update the model, then model tells the Presenter if that succeed or not, and Presenter tells the View to show the right message.
MVVM - Model View ViewModel
with the rise of reactive paradigm, it was clear that we can provide more separate of concerns in UI Applications by just observing the changes and behave on it.
so for example there is a click in view that need to call an api to get latest tv shows.
this view click will be observed at the ViewModel, ViewModel interact with the model to get the data, and finally ViewModel post those data on the view using other observer ..
so in short, View observe ViewModel to get UI updates, and ViewModel observe View to call the right action with the Model. Observer pattern has proved his worthy in decoupling logic so here you go a new Pattern.
So after talking about the most popular architecture patterns, each one has tried to decouple the UI code from the business code. but the previous patterns doesn't bound updating UI with different states in the same time.
if you had an issue that related to the loading appear with an error message showed at the same time, you will understand what I'm talking about, so to maintain UI state, you have to do extra effort looking what you wrote wrong causing those kind of issues.
MVI - Model View Intent
MVI is based on an old idea called finite state machine, any system or component has predictable, set of states is a finite state machine.
in MVI any update to the UI is defined by new state, you could find this is overwhelming, but imagine that you have a screenshot for each time UI changes, that's the state. you can debug, test, reproduce the state issues now.
how to achieve this, that's the MVI in practice.
any user interaction with the UI, is defined in MVI by an Intent, Intent is what the user need from this action, it could be star a movie, refresh the screen, it even could be opening the screen, in that case the Intent is an initial intent to show the screen with all required data.
which component get those Intents to act according on them, that what you define .. you could use a Presenter or a ViewModel, it doesn't matter, MVI is more a practices than using a new middle component.
I'll continue with ViewModel, ViewModel will get those intents, decide which usecase to call (Model behaviors).
all usecases pass by summer function in the ViewModel, that decide which state that needs to be reflected to the View, it provides you with previous state too, so you have the previous and the new state to update the screen, which reduce the rendering updates, and View get only the new hints to update itself.
and finally MVI is uni directional flow, it starts with the View and ends with the View.
... View -> ViewModel/Presenter -> Model -> View -> ...
MVI is different in the way of managing the state, it's a combination of several ideas to build more stable, and testable app.
A really great breakdown is here: https://academy.realm.io/posts/mvc-vs-mvp-vs-mvvm-vs-mvi-mobilization-moskala/. At it's core, MVI is taking the ideas of MVVM (stateless UI state), separate business logic and models, and putting the reactive framework on top of it. Making things streams of events instead of discrete actions, making receiving elements consumers of transformed streams instead of presentation elements, and making state a read-only, disposable thing that is acted upon explicitly in a very structured way.
This requires that you take a functional approach to writing your application, especially the UI/View part of things. State is not modified, new state is calculated from an intent and a series of use-cases. This is fairly well explained here: https://proandroiddev.com/mvi-a-new-member-of-the-mv-band-6f7f0d23bc8a.
It is intended to address the growing complexity of modern UI applications, who have a non-trivial amount of client-side state that needs to be managed explicitly. As most experienced programmers know, the most complex failures come from state that is being modified in an unexpected way. This state manipulation can result in "invalid" states that your application cannot handle, which is effectively a crashed application. MVI addresses this by making state transitions explicit and carefully structured so that they system never comes to an invalid state, and the state is always understandable.
This question already has answers here:
Scoping a viewmodel to multiple fragments (not activity) using the navigation component
(4 answers)
Closed 3 years ago.
Using the new Navigation Architecture Component, I've got a single activity as a navhost with multiple fragments for my screens. Right now I have an EditProfileFragment where the user can click a button and another fragment opens, with a list of countries to choose from. Let's say I want to share the result of that country selection back to the EditProfileFragment. The general idea is that I'll have a single EditProfileViewModel for all "edit profile" actions.
How do I share the selected country between those fragments? I'm thinking using a shared viewmodel, but I'm hesitant scoping it to the activity because I don't want it to persist when the user completes the "edit profile" flow.
Are there any other clean/recommended approaches I should consider? Maybe a singleton that temporarily holds that value?
It's easier with a shared view model indeed, but as you said, it comes with other concerns like scoping the view model to a higher context for simple information exchange.
IMHO shared view model is not a bad approach in certain scenarios. I was working on an app which has 5 tabs, first tab was like a summary of 2nd and 3rd ones. It was a good choice to use shared view model, since I was just reusing the data, just changing the number of items adapter shows in corresponding views, logic was being reused.
It sounds like you have common logic / items in your profile & profile edit page. I don't know how many, but if you feel like it's not enough to share a view model between these two, remember just because you are using view models doesn't mean you have to use them to share / store / pass around some data. For example :
Navigate to previous fragment with acquired data.
You can save "profile" to persistence and change what's stored. When your view model for profile is (re)created, it gets the latest value from persistence.
You can update your profile in server directly, and fetch it again on profile.
You can mix these two above.
Answering my own question on how I resolved this for future reference:
Because I wanted to keep the 1-to-1 relationship between ViewModel-View(controller)/Fragment, I went with a UserRepository that holds a "temporary state" object for cases like this.