I have multiple Activities with the same CardView. To inflate this CardView I reuse the ViewHolder in my adapter. Now I'm trying to handle a click on the ViewHolder with setOnClickListener() and I need to save the Model represented by CardView into the database using a Repository. So for MVVM, the repository can communicate only with ViewModels and Databases or other resources, but every Activity has a different ViewModel so I couldn't pass the ViewModel to the Adapter to update the Model into the Database.
So I'm thinking that the adapter that I reuse, needs only one ViewModel for the database actions indifferently from the Activity that uses it.
So I need a static method in the main ViewModel that saves that Model.
This approach is correct for the MVVM pattern?
I don't know if I understand your question correctly but I guess that you want to somehow send a data from recyclerview adapter to your database.
"so I couldn't pass the ViewModel to the Adapter to update the Model into the Database"
You should never pass any viewModel to the adapter class because you will tightly couple them together and they wouldn't be reusable anymore.
In your case you should send data from adapter class and receive it in activity. Then activity should call viewModel to update specific data and viewModel will then call repository which will access database and save data.
It sounds complicated but it is well organised and you can reuse all components in many activities/fragments because they are not depending on each other. Adapter sends events that are received by your activity but the adapter does not know (and shouldn't know) which activity will receive the data. If you would pass viewModel as a parameter to the adapter class then it couldn't be used in activities that have different viewModel.
P.S Try to not use activity for all your views, in Android we have a Fragment component which is very useful in that case.
Useful links
fragments https://developer.android.com/guide/fragments
MVVM https://proandroiddev.com/understanding-mvvm-pattern-for-android-in-2021-98b155b37b54
Related
I have a lot of fragment base architect component.
Is this true that I create ViewModel for per fragment? or I should create one ViewModel for all fragment?
Saw many project that uses ViewModel for each Activity, and they pass them to their fragments if needed.
Same goes for me, but figure out what functions that Activity will do, and then build a ViewModel based on that functions:
Activity/Fragments that create an object.
Activity/Fragment that fetch a list.
Activity/Fragment that deal with Objects, like delete, update.
You can pass ViewModel to fragments. Also you can use inheritance with your ViewModels.
My question is kind of not strictly precised. I have a Fragment with list of items that are backed up by REST API service:
GET /api/items
I have a ItemsViewModel class, ItemsProvider with LiveData objects and APIService that get the items from REST service. The implementation of ListFragment observes the ItemsViewModel and its state.
Now I have a question. How do you implement inserting data into ViewModel in your implementations? How do you handle state update?
You can take LiveData<List<? of items>> as MutableLiveData inside ItemsViewModel.
Now, when you've new items, you need to set your LiveData value.
You need to create an observer to that inside of your activity/fragment where you needed.
TL;DR
How do I deal with Activities that actively change data (for example through an EditText)? Do I keep saving their state in the SavedInstanceState on rotation and only use the ViewModel when all of the fields are ready, or is there a way to make the ViewModel responsible for checking/holding/using the UI's data?
Question
I'm developing my application using Google's Arch. Components, and writing my latest class I've noticed I'm not really sure on what the best practice is when handling, say, data coming from an Activity form.
Example
I have a POJO made of title, description, location, type
I have an Activity with four EditText: title_et, description_et, location_et, type_et.
My ViewModel, through a Repository (irrelevant here), can send an object to the Database when the sendObject function is called.
How I'm doing it now
The activity has the mTitle, mDescription, mLocation, mType.
On rotation, the activity saves all of the EditText values in the savedInstanceState bundle, and it loads them again populating the views.
When the user wants to send the object, it clicks a button and the activity calls the function viewModel.sendObject(mTitle, mDescription, mLocation, mType) after the necessary checks.
Problems with this approach
The activity is responsible of holding/checking all the data of the EditTexts, basically making the ViewModel only responsible of interacting with the Repository.
What I'd like to accomplish
Ideally, I'd want to make the Activity only responsible of the UI, delegating everything to the ViewModel.
This way I could call sendObject() and the ViewModel would have already all of the data needed.
The LiveData situation
Right now the ViewModel has only one instance of LiveData, inside that there is a Resource (which is taken from here) and it's used to "tell" the Activity that new data has arrived or an error occurred.
This approach works fine in all Activities that just receive data from the network and display them. What do I do when I want to synchronise data coming FROM the Activity? Do I use one LiveData for each field and use that to display potential errors?
I've read most of the samples but all of the Activities there are passive.
Conclusion
Thanks to anyone who takes the time to help.
You can either separate the logic into a model string class with another class containing all your String values for the edit text fields are just assign the String values at the top of your class.
You can have a LiveData of your model in the ViewModel and alter it from the View (Activity/UI). The downside is that to update the LiveData, you need to copy whole Model, edit it and post it back to live data.
The second way is to dissect Model's components in the ViewModel into individual parameter LiveDatas. Later when form is submitted you can reconstruct the Model.
What you can do for native fields is use data binding. For other you need manually update LiveData from the View with listeners etc.
I'm creating a sample app (Last-Mvvm) to learn (and possibly show) the usage of mvvm pattern, using Android data binding.
I have an activity with my ViewModel object inside. I have also a RecyclerView adapter, which contains an arraylist of items that are converted to another Viewmodel. I want to save the state of the list inside the adapter (for rotation changes).
So: where should I save it? inside the activity? Or in the viewModel of the activity? Or somewhere else?
Also, there is another thing that isn't really clear.
Is it fine to perform rest calls (through Retrofit) or database calls directly from the viewModel (since i'd use interfaces), or would it be better to make an interface that the view (activity) implements and performs all the calls?
I will try to explain
First. So: where should I save it? inside the activity? Or in the viewModel of the activity? Or somewhere else?
and
Second. Is it fine to perform rest calls (through Retrofit) or database calls directly from the viewModel (since i'd use interfaces), or would it be better to make an interface that the view (activity) implements and performs all the calls?
on example from article.
On the schema below you can see implementation of OnClickListener and OnLongClickListener for RecyclerView item.
doted lines is a links
solid lines is a method calls
How it works
ViewHolderWrapper works as ClickListener for root view of ViewHolder. Depending on implementation ViewHolderWrapper can be proxy for HolderClickObservable or depending on SelectionHelper, ViewHolderWrapper can manually highlight selected item.
SelectionHelper is responsible for saving selection state and notify SelectionObserver about changes.
Listener (Adapter in this case) is responsible for highlighting of selected items and for updates.
Summarizing
First. You can restore adapter state via activity with methods onSaveInstanceState() and onRestoreInstanceState().
Second. You need to create lightweight ViewHolder which only responsible for binding data to view. Actions can be performed at adapter or activity.
See also example application
I am working on a Android app which have 5 fragments and some java classes.
I have to be able to read and edit an arraylist containing pojo's from across these fragments and classes. For example updating from the internet and then updating recyclerView in one of the fragments or sorting the objects in a recyclerView in one fragment and have those changes updated in the recyclerView in another fragment.
I have been looking at notifyDatasetChanged, but cannot get it right, when starting an update in the background and then wants it to update onSucceed in the active fragment.
I have been looking on RxJava with the Arraylist as observable, but once again I ran into problems when I wanted to subscribe from multiple fragments.
And of course I did a arraylist in a singleton, but I am pretty sure that is bad coding :-)
I would put the data that is going to be accessed by all of the fragments in a Service. Each Fragment can bind to the service to retrieve a reference to the data and to register a listener (you will have to make a custom one to handle the events that you are interested in) that will tell each Fragment to update its own view. Each Fragment would implement its own Adapter that would wrap the shared data that lives in the Service.