how can i share viewModel between Activities? - android

I'm learning Android ViewModel now.
and I have MainActivity and RegisterActivity which can type name, age, and phone number in there.
after typing that information in the RegisterActivity, I put that info into a ViewModel and click a button and finish the RegisterActivity.
the thing is, I want to show the info in MainActivity.
so how can I share the viewModel between the two activities?
what a concept do I have to use?

You can't share a ViewModel across Activities. That's specifically one of the downsides of using multiple activities as per the Single Activity talk.

You can put the data you want to keep for the MainActivity into your Application class or use SharedPreferences.

viewModel cannot be directly shared between activities however, if u store viewmodelfactory in application class and retrieve factory object from activities and access viewmodel then u can share state of view model, i checked this senario in featureModule app, it worked

ViewModel has application level lifecycle. If you use single viewmodel with two or more activities then after attaching with first activity when it get attached with other one. then there might be some problem.

Related

How to access the Login state from everywhere? Jetpack Compose + MVVM

I'm building my app in Jetpack Compose and use one ViewModel for every feature/screen.
Now I need to access the login state from everywhere inside the app, I also have a coin system where I need access to from every screen.
How do I accomplish this?
My first idea was to put the login state and coin state inside a "MainViewModel" and then use this in every Screen for example in my "SettingsScreen" composable use "SettingsViewModel" and "MainViewModel".
But I'm not sure if this is a good practice to use two viewModels in one screen.
How can I have access to the Login state and the Coins in every screen?
You can use the singleton pattern to access your login credentials as either a global object or (better) a dependency that you inject into ViewModels which require that login state dependency. If you're using Dagger the #Singleton annotation is helpful
You could create a base ViewModel that injects that login state object into any class that inherits it.
If you're using the single activity pattern, you could scope your MainViewModel to that Activity and then access ViewModel from any fragment that is also scoped to that same Activity. This would be my preferred approach.

How to create a shared variable between fragments in kotlin

currently, my Kotlin based application consists of a single activity, 3 fragments and a navigation (with navigation drawer) between them.
How do I add a variable, which will be initialized in the start of the application, will be visible in all fragments, and can be updated in one of them?
a simple int or string for that matter so it should be with little overhead as possible, yet i'd like to follow correct coding conventions. Please elaborate on the correct function to perform the initial variable value, how to bind each fragment textview to it, and the correct way to set the new value.
Thanks!
Create ViewModel and fragments use viewmodel like this
val viewModel: YourViewModel by activityViewModels()
in that case your viewmodel's scope is the same as activity scope.
For more information please refer to this link

Best way to pass data needed for a later (not following) fragment?

I have an application that needs to collect some data before doing it's main job.
So, the first fragment collects data, the second fragment collects data and then the third fragment uses the data.
The problem is: data in the first fragment is uncorrelated to the data I collect in the second fragment.
How can I pass the data from the first fragment to the third? Should I incrementally pass all the data I collect in the next fragment arguments, or should I store them elsewhere? I'd really like to know what the best practice is.
explicative image
I won't use a database, since I don't need to permanently store the data.
Thank you!
As for any best practices, the best answer is "it depends".
If your app is really small and simple then it's okay to pass data from one screen to another in the arguments bundle.
A more complex approach is to store data somewhere outside of these Fragment lifecycles.
It's a general rule you can implement as you want. A couple of examples below:
Data can be stored on Application class level. Application class runs for all application lifecycle. Every fragment can get Application instance from its activity like activity?.getApplication().
Data can be stored on Activity level if all fragments run in a single activity. Activity can be obtained from Fragment using activity or requireActivity().
Data can be stored on a parent fragment level if all fragments run in this parent fragment. It can be obtained from child fragments using parentFragment.
All these approaches suppose you to cast some "parent" thing to specific interface or implementation. For example, if your fragments run in the MainActivity which is stores some val data: Data as its property, then you should use it something like this: (requireActivity() as MainActivity).data
Clarification on a couple of popular answers:
The Shared ViewModel is just a special case of activity-level approach as ViewModel instance is stored in Activity scope.
The SharedPrefrences like any "database" approach is a special case of application-level approach as SharedPreferences is stored on application-level (in the file storage) no matter where you create its instance. (And SharedPreferences persists data across application starts, so it's not your option)
In addition to mentioned "Shared ViewModel" technique, Androidx introduced new "Fragment result Api" starting with "Fragment" library v1.3.0-alph04 (currently in beta) which could be used for communication between pair of Fragments or Activity-Fragment.
A Fragment/Activity set a listener in FragmentManager by specifying a key and other Fragment/Activity send data (in form of a Bundle) to the listener with that key. If there's no listener for the key, FragmentManager keeps newest data until a listener gets registered.
Pay attention that listener and result must be set on same FragmentManager instance.
I my opinion, its good for signals (events), not for sharing data. A situation I found it useful, was sending "onWindowFocusChanged" from Activity to Fragment. In case of sharing data, Shared ViewModel is better.

Is it possible to call ViewModel methods from fragments through an Activity or is it a bad practice?

I have an Activity and 4 fragments in it. At first I wanted to do for each fragment of the ViewModel. But the situation is such that I also need ViewModel for Activity. I want to know if it would be an error to make the ViewModel just for the Activity and call the necessary methods from the fragments using getActivity? For example, call getActivity().myViewModel.callMethod() at fragment? Wouldn't this approach be wrong?
Yes, you can use the ViewModel of the Activity at a fragment, but not like that getActivity().myViewModel.callMethod(). It should be like this
YourViewModel viewModel = ViewModelProviders.of(getActivity()).get(YourViewModel.class);
And it's a good practice to share data between fragments.
Official doc of Google says
That way, when the fragments each get the ViewModelProvider, they
receive the same SharedViewModel instance, which is scoped to this
activity.
This approach offers the following benefits:
The activity does not need to do anything, or know anything about this
communication.
Fragments don't need to know about each other besides
the SharedViewModel contract. If one of the fragments disappears, the
other one keeps working as usual.
Each fragment has its own lifecycle,
and is not affected by the lifecycle of the other one. If one fragment
replaces the other one, the UI continues to work without any problems.

how to use viewmodel singleton for activities?

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

Categories

Resources