I have a restaurant app with two main fragments each with their own viewmodels -
LiveList fragment & viewmodel that retrieves a list of restaurants from the internet and displays them in a recyclerView.
SavedList fragment & viewmodel that displays the saved restaurants from a database and deals with all the database interactions
What I want to do is when the user clicks the star next to each restaurant in the LiveList for that restaurant to be added to my SavedList database.
Can I:
1- simply call a reference of SavedListViewModel.addRestaurant from LiveListViewModel ?
2- need to change to a shared ViewModel approach?
3- make the addRestaurant an interface that the LiveList can access?
4- let SavedListViewModel observe a piece of Livedata from LiveListViewModel and tie that Livedata to the selected restaurant?
5- none of these approaches viable?
Make a shared view model in activity scope.
viewModels gives you the ViewModel instance scoped to the current fragment. This will be different for different fragments.
activityViewModels gives you the ViewModel instance scoped to the current activity. Therefore the instance will remain the same across multiple fragments in the same activity.
https://developer.android.com/codelabs/basic-android-kotlin-training-shared-viewmodel#4
Related
My app has an activity on which many fragments are placed for different pages.
Some fragments have a recyclerView that data given via a viewModel.
Now, I would first create an instance of the viewModel in each fragment and put the data in the recyclerView using observer and LiveData, but this caused LiveData observer is being triggered two times.
After that, the idea came to me to create a static instance of the viewModel in the activity class to solve this problem and use it in different fragments. It worked, and LiveData observer triggered once.
Now my question is, is it right to use a static instance of viewModel in MainActivity (and use it from fragments)?
If not, then what should I do to solve the problem(Trigger the observer twice)?
I have know that an Activity/Fragment has to create a ViewModel, and the ViewModel can be created from a ViewModelFactory. And the ViewModel itself are using a data repository which handles the data from either database or network. And the ViewModel is not a singleton.
For example, I have an activity which has two fragment, fragment A and fragment B, and I'm only able to access them one by one. In the fragment A, I load some data from a repository which came from a network or database. When I navigate to fragment B, the data in a fragment A is lost, so I have to load it back from a network or database which takes time. Because of that I would like to store my data somewhere in the runtime.
My question, what is the best approach to solve this problem? Is it okay to create a singleton in the repository?
you need to use a shared viewModel, a ViewModel that is shared between your fragments and survives navigating between certain fragments.
Implementation depends on what you use in your project. you can create a ViewModel in the activity and access them from your fragments and put the shared data in this ViewModel. or if you are using navigation component you can have a shared ViewModel per nav graph. and with dagger and koin you can define a costume scope for your ViewModel to survive. see these links:
Share data between fragments
Share data between fragments with shared viewModel
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.
In my app I need to load a feed of some data from server(using retrofit) that is loaded in a dedicated viewmodel.
What happens currently is that the viewmodel calls the repository in its constrcutor, and then once the data is fetched , the observing fragment in the main activity is notified and changes the ui accordingly.
However, suppose I want to fetch that data during the splash/launcher activity, what would be the implementation for it using MVVM?
I mean, since the viewmodel is associated with only one activity, we can't share the same viewmodel accross both activities.
So how could we load the remote server data in Launcher Activity, and then use that in Main Activity?
What are the best practices in this case?
Relation between ViewModel and View is one-to-many. It's a difference from MVP. You can share your ViewModel with other Views and can use separate ViewModels for every View.
UPD: Seems like you can create 1 activity, the content of your Splash and Main activity will be fragments. So, by going from splash to main you will just swap fragments. If you will create a ViewModel in both of fragments as follows:
ViewModelProviders.of(getActivity()).get(MainViewModel.class);
instead of:
ViewModelProviders.of(this).get(MainViewModel.class);
You will get the same instance of ViewModel in both fragments.
MyApp need hold a User object in whole context,A,B,C activities'xml use this User object,when A edit User,I want B and C notifyChange,how to deal this problem with databinding,livedata and viewModel?
Formerly I make User.class extend BaseObservable,but POJO will be very troublesome and must not be a null,sometimes User maybe null such as not login.
Now I Change to use LiveData, make Pojo simple and not extend BaseObservable,but when A edit,B and C not work,I think i need ABC use same viewModel instance in memory,but this will cause viewModel's onClear() trigger manytimes.
Another way is to have one singleton repository to hold your user data and each viewModel can have that repository and share the same data between activities.
Based on this part of the documentation:
https://developer.android.com/topic/libraries/architecture/livedata#extend_livedata
The fact that LiveData objects are lifecycle-aware means that you can share them between multiple activities, fragments, and services. To keep the example simple, you can implement the LiveData class as a singleton as follows:
You can create a singleton for your view model like I did here:
companion object{
private lateinit var instance: ViewModelProfile
#MainThread
fun getInstance(userId: String): ViewModelProfile{
instance = if(::instance.isInitialized) instance else ViewModelProfile(userId)
return instance
}
}
Then I call it and get instance anywhere like this:
val profileVModel = ViewModelProfile.getInstance(user.uid)
If you want to share common ViewModel between ABC activities, then it is suggested to keep them as 3 fragments in a single Activity, create ViewModel of that Activity which can be shared among all three fragments A, B, and C.
Also what you are trying to achieve with activities is like this, suppose you have done some operation in activity A, if you want Activity B and C to get notified about them then they need to be running to get notified, which won't be happening, so instead you should use Intent or Bundle to pass needed information when the activity get started.
Updated
There are other ways as well to achieve similar kind of functionality like,
Event Bus
RxJava Subjects (refer this)
Android State by Evernote (refer this)
This will allow you to have application level access of state, which can be accessed by any Activity or Fragment