How to get an Instance of ViewModel in activity in 2020/21?
Asked Answered
S

10

50

I am new to the mvvm pattern. I created a ViewModel for the main activity. Now I want to get an instance of the ViewModel in the main activity.

Most Tutorials and answers here on Stackoverflow suggest using ViewModelProviders.of(..., but this is depreceated.

So according to this question on stackoverflow: ViewModelProviders is deprecated in 1.1.0 main activity in onCreate, I do the following (and I could swear I already had it running): mainActivityViewModel = new ViewModelProvider(this).get(MainActivityViewModel.class);

However, I am getting an error telling me, that no suitable constructor has been found.

error: no suitable constructor found for ViewModelProvider(MainActivity)

Alternatively to make absolutely clear, that the MainActivity shall be the ViewModelStoreOwner, I created a variable ViewModelStoreOwner vmso = this; and put that variable into the constructor like so: mainActivityViewModel = new ViewModelProvider(vmso).get(MainActivityViewModel.class);

Shaddock answered 28/1, 2020 at 16:3 Comment(4)
are you sure your reference to this is correct? If it's a Fragment you'll need to use getActivity() instead of this iirc, and if you are in a listener or anonymous class you will have to do MainActivity@this etc etcBrevity
I am calling the method in onCreate() of the main activityShaddock
Does this answer your question? As ViewModelProviders.of() is deprecated, How should i create object of ViewModel?Willywillynilly
No, it doesn not. The described solution in Java code is boardViewModel = new ViewModelProvider(this).get(BoardViewModel.class), which is equivalent to mainActivityViewModel = new ViewModelProvider(this).get(MainActivityViewModel.class); which I already tried, but seems to be no suitable constructor.Shaddock
P
53

You should update your gradle file to:

implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'

And due to this change you can pass Activity to the constructor you mentioned:

mainActivityViewModel = new ViewModelProvider(this).get(MainActivityViewModel.class);
Painstaking answered 3/4, 2020 at 11:58 Comment(0)
S
20

Using Fragment-ktx libr in your app you can get viewModel as below

First Update Gradle File as app -> build.gradle

implementation 'androidx.fragment:fragment-ktx:1.1.0'

// get ViewModel in Activity or Fragment as

private val viewModel: MainActivityViewModel by viewModels()

// If you want to get same instance of ViewModel in ChildFragment as

 private val viewModel: MainActivityViewModel by viewModels(
    ownerProducer = { requireParentFragment() }
)
Sitzmark answered 23/7, 2020 at 19:16 Comment(2)
Fragment-ktx is for fragments. We need activity-ktxSewage
And what if Activity is derived from androidx.appcompat.app.AppCompatActivity and NOT the androidx.activity.ComponentActivity?Cony
E
20

Based on Android documentation, you can do this:

KOTLIN

implementation 'androidx.activity:activity-ktx:1.3.1'

val model: MyViewModel by viewModels()

JAVA

implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'

MyViewModel model = new ViewModelProvider(this).get(MyViewModel.class);
        
Electronegative answered 5/10, 2021 at 13:49 Comment(0)
C
18

Use val viewModel by viewModels<TheViewModel>() in Activities and val viewModel by activityViewModels<TheViewModel>() in fragment to obtain the same viewmodel from the activity (so sharing the viewmodel).

This is part of androidx now

Corriveau answered 24/9, 2020 at 7:36 Comment(1)
Thanks! This is probably obvious to most people, but you can also do val viewModel: ThisViewModel by viewModels() and val viewModel: ThisViewModel by activityViewModels()Addiel
C
6

Get ViewModel In New Way

MainActivityViewModel mainActivityViewModel;
    mainActivityViewModel= new ViewModelProvider(this).get(MainActivityViewModel.class);
Chalcopyrite answered 29/9, 2020 at 21:6 Comment(1)
This is Java. We use Kotlin.Sewage
S
2

For now, the only thing working for me was to use: MainActivityViewModel = new ViewModelProvider(this, new ViewModelProvider.NewInstanceFactory()).get(MainActivityViewModel.class);

However, I am still thankful for any advice, how this can be done different using new ViewModelProvider(this).get(MainActivityViewModel.class);

Shaddock answered 1/2, 2020 at 17:22 Comment(2)
This still fails, but this time with java.lang.RuntimeException: Cannot create an instance of class xxx insteadGravimetric
Did you follow the first answer ?Cascade
L
2

You can use a ViewModelFactory:

val viewModelFactory = VMFactory(requireActivity().application)
viewModel= ViewModelProvider(requireActivity(),viewModelFactory).get(MainViewModel::class.java)

VMFactory code:

class VMFactory(application: Application) : ViewModelProvider.NewInstanceFactory() {

    val _application: Application=application

    @NonNull
    override fun <T : ViewModel?> create(@NonNull modelClass: Class<T>): T {
            return  MainViewModel(_application) as T
    }
}

Please note that here my MainViewModel extends AndroidViewModel and hence requires application as the input parameter.

Lashawn answered 15/7, 2020 at 6:26 Comment(0)
M
0

Duplicate question and already answered here

Simply replace:

This:

boardViewModel = ViewModelProviders.of(this).get(BoardViewModel::class.java)

With this:

boardViewModel = ViewModelProvider(this).get(BoardViewModel::class.java)
Metzger answered 30/1, 2020 at 17:59 Comment(3)
If this question is a duplicate, please refrain from answering and flag as so insteadWillywillynilly
Plus, your suggestion does not work but fails with error: no suitable constructor found for ViewModelProvider(MainActivity) as described in the questionGravimetric
main thing to notice here is the line that we need to replace is ViewModelProvider not ViewModelProviders. notice the 's' here at the end.Pisgah
G
0

I had similar problems and in the end found out I missed off the "extends ViewModel" within the class definition, so it should look like this:

public class ViewModelClass extends ViewModel
{
    // Tracks the score for Team A
    public int scoreTeamA = 0;

    // Tracks the score for Team B
    public int scoreTeamB = 0;
}
Groves answered 27/12, 2020 at 9:18 Comment(0)
A
-1

ViewModel viewModel = ViewModelProviders.of(this).get(ViewModel.class);

Android Support library version is depreciated. So you need to make sure that you import Androidx. And you need to implement androidx dependency in Gradle file.

It is not advised to create a new ViewModel object with "new" keyword.

Abel answered 28/1, 2020 at 18:2 Comment(1)
According to the developer guides, ViewModelProviders is depreceated and it is recommended to use the constructors directly. developer.android.com/reference/androidx/lifecycle/…Shaddock

© 2022 - 2024 — McMap. All rights reserved.