how to instantiate ViewModel In AndroidX?
Asked Answered
B

10

75

I want to initialize ViewModel in Activity using androidx library

I have tried what documentation says but it is not working. the ".of" is not resolved.

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.ViewModelProvider
import com.example.myapplication.databinding.ActivityMainBinding`

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding: ActivityMainBinding = DataBindingUtil.setContentView(
            this, R.layout.activity_main)
        binding.setLifecycleOwner(this)

        var model = ViewModelProvider.of(this).get(SheduleViewModel::class.java)

    }
}

of is not resolved, maybe there are another way to do it in androidx

Blinkers answered 22/1, 2019 at 17:23 Comment(7)
What is this? Is it an AppCompatActivity or FragmentActivity? Or is it an AndroidX Fragment? Or is it something else?Cyb
You need to import ViewModelProviders to find ofWonderwork
it appCompatActivity, I can Import ViewModelProvider but it does not contain of methodBlinkers
Please give a complete code example. Show the surrounding class and appropriate imports. Also, copy-paste the exact error message.Extroversion
You'll need to use class ViewModelProviders in-spite of ViewModelProvider.Appease
thank you brothers, I really appreciate itBlinkers
Add this dependency into your build.gradle file: implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'Simmer
C
143

Updated answer:

Things changed a little bit, as the previously needed dependency - ViewModelProviders - got deprecated (see the old answer for details). You can now use the ViewModelProvider constructor directly.

So, in this case, the answer would be:

private val viewModel = ViewModelProvider(this).get(SheduleViewModel::class.java)

Note that, however, if you include the androidx.activity:activity-ktx:$Version dependency (a few of the commonly used AndroidX dependencies already include it for you), you can make use of property delegation:

private val viewModel: SheduleViewModel by viewModels()

Which internally will use ViewModelProvider and scope your ViewModel to your Activity. It's just a more concise way of writing the same thing. You can do the same for a Fragment by including the androidx.fragment:fragment-ktx:$Version dependency instead (again, commonly already included by other AndroidX dependencies).

Both the ViewModelProvider constructor and by viewModels() also accept a factory as a parameter (useful for injecting your ViewModel):

private val viewModel = 
    ViewModelProvider(this, viewModelFactory).get(SheduleViewModel::class.java)

and

private val viewModel: SheduleViewModel by viewModels { viewModelFactory }

Use the one that best suits you.

Old answer:

Add the androidx.lifecycle:lifecycle-extensions:$lifecycleExtensionsVersion dependency in order to import ViewModelProviders.

Clothesbasket answered 22/1, 2019 at 17:30 Comment(5)
I imported viewmodelProviders. I can see itBlinkers
If your code is per your edit, you're missing import androidx.lifecycle.ViewModelProviders. It has an s at the end. You need both import androidx.lifecycle.ViewModelProviders and import androidx.lifecycle.ViewModelProvider.Clothesbasket
ViewModelProviders is deprecated, migrate to ViewModelProviderDisaster
Can you give the syntax in JavaIsidoro
@Isidoro it's pretty much the same thing: SheduleViewModel viewModel = new ViewModelProvider(this).get(SheduleViewModel.class);Clothesbasket
B
21

Updating ViewModel to Lifecycle Version 2.2.0 and Above

The ViewModels (VMs) may theoretically be initialized as class level instance variables using the Kotlin extension library import androidx.fragment.app.viewModels method by viewmodels(). By initializing the VM as a class level instance var it can be accessed within the class.

Question: Is there a downside to initializing the VMs as class level instance variables instead of inside onCreate?

When creating the VMs with the extension function inside onCreate the VMs are only scoped within onCreate and extra code is required to reassign the class level instance variables.

See documentation

Initialize VM as Class Instance Val

class Fragment : Fragment() {
    private val viewModel: SomeViewModel by viewModels()

    private fun observeViewState() {
        viewModel.feedViewState.observe(viewLifecycleOwner) { viewState ->
            //viewState used here.
        }
    }
}

Initialize VM in onCreate and Reassign Class Instance Var

class Fragment : Fragment() {
    private lateinit var viewModel: SomeViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val viewModel: ContentViewModel by viewModels()
        this.viewModel = viewModel
    }

    private fun observeViewState() {
        viewModel.feedViewState.observe(viewLifecycleOwner) { viewState ->
            //viewState used here.
        }
    }
}

Passing Arguments/Parameters

// Override ViewModelProvider.NewInstanceFactory to create the ViewModel (VM).
class SomeViewModelFactory(private val someString: String): ViewModelProvider.NewInstanceFactory() {
    override fun <T : ViewModel?> create(modelClass: Class<T>): T = SomeViewModel(someString) as T
} 

class SomeViewModel(private val someString: String) : ViewModel() {
    init {
        //TODO: Use 'someString' to init process when VM is created. i.e. Get data request.
    }
}

class Fragment: Fragment() {
    // Create VM in activity/fragment with VM factory.
    val someViewModel: SomeViewModel by viewModels { SomeViewModelFactory("someString") } 
}

Enabling SavedState with Arguments/Parameters

class SomeViewModelFactory(
        private val owner: SavedStateRegistryOwner,
        private val someString: String) : AbstractSavedStateViewModelFactory(owner, null) {
    override fun <T : ViewModel?> create(key: String, modelClass: Class<T>, state: SavedStateHandle) =
            SomeViewModel(state, someString) as T
}

class SomeViewModel(private val state: SavedStateHandle, private val someString: String) : ViewModel() {
    val feedPosition = state.get<Int>(FEED_POSITION_KEY).let { position ->
        if (position == null) 0 else position
    }

    init {
        //TODO: Use 'someString' to init process when VM is created. i.e. Get data request.
    }

     fun saveFeedPosition(position: Int) {
        state.set(FEED_POSITION_KEY, position)
    }
}

class Fragment: Fragment() {
    // Create VM in activity/fragment with VM factory.
    val someViewModel: SomeViewModel by viewModels { SomeViewModelFactory(this, "someString") } 
    private var feedPosition: Int = 0

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        someViewModel.saveFeedPosition((contentRecyclerView.layoutManager as LinearLayoutManager)
                .findFirstVisibleItemPosition())
    }    

    override fun onViewStateRestored(savedInstanceState: Bundle?) {
        super.onViewStateRestored(savedInstanceState)
        feedPosition = someViewModel.feedPosition
    }
}
Baggett answered 6/2, 2020 at 17:34 Comment(0)
F
10

For me, the only thing that worked:

implementation 'androidx.fragment:fragment:1.2.4'
Furmark answered 5/6, 2020 at 18:39 Comment(0)
P
7

PS. This is for someone who is using java and got stuck for a while like I did and this SO answer comes up in google all the time.

Apparently, the API has change as of this date (6 May 2020), I had to do this to get it working.

// 1. Create a ViewModel Class Let's call it AppStateViewModel

// 2. Put below code Inside Activity onCreate like this:
ViewModelProvider.Factory factory = new ViewModelProvider.NewInstanceFactory();
appStateManager = new ViewModelProvider(this, factory).get(AppStateViewModel.class);
Polemic answered 6/5, 2020 at 10:59 Comment(2)
Thanks a lot! That's what i was missing and most of the answers above would have taken even more time to falsify. If you are using up to date dependencies, this is probably your answer. The documentation developer.android.com/topic/libraries/architecture/livedata has not been updated to track the api change at the time of this commentWrap
Thank you so much. This was what I was looking for and I couldn't find it anywhere. It was all kotlin or deprecatedGoodkin
G
7

In your app gradle file make sure you have added below dependencies:

For Activity use:

implementation "androidx.activity:activity-ktx:1.4.1"

For Fragment use:

implementation 'androidx.fragment:fragment:1.4.1'
Giesser answered 7/5, 2022 at 12:4 Comment(0)
P
5

ViewModelProviders: This class is deprecated. Use the constructors for ViewModelProvider directly.

Examples in Kotlin

This is how you can use ViewModelProvider directly:

If your view-model is extending AndroidViewModel with just one argument, the app - then you can use the default AndroidViewModelFactory and you don't have to write a new Factory. Example:

// Activity / fragment class
private lateinit var viewModel: MyOwnAndroidViewModel

    // onCreate
    viewModel = ViewModelProvider(
            this,
            ViewModelProvider.AndroidViewModelFactory(application)
        ).get(MyOwnAndroidViewModel::class.java)

If your view-model is only extending the ViewModel without extra arguments then use the NewInstanceFactory().

// Activity / fragment class
private lateinit var viewModel: MyOwnViewModel

    // onCreate
    viewModel = ViewModelProvider(
            this,
            ViewModelProvider.NewInstanceFactory()
        ).get(MyOwnViewModel::class.java)

Adam's answer above covers other variations as well.

Disclaimer: Still learning basic Android development - if there's any problem with the code, let me know in comments.

Providing answered 8/5, 2020 at 20:40 Comment(1)
For some reason I was asked to use [MyOwnViewModel::class.java] instead of .get(MyOwnViewModel::class.java)Alpaca
A
4

(How to) Use ViewModel from Android Architecture Component :

  1. Add the Google Maven repository (Optional, just verify that)

    Android Studio projects aren't configured to access this repository by default.

    To add it to your project, open the build.gradle file for your project (not the ones for your app or module) and add the google() repository as shown below:

    allprojects {
        repositories {
            google()
            jcenter()
        }
    }
    
  2. Declaring dependencies

    Open your app-level build.gradle file,

    Go to dependencies{} block

    Put implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version" for AndroidX version, $lifecycle_version here is latest version defined.

    For Pre-AndroidX use implementation "android.arch.lifecycle:viewmodel:1.1.1" (1.1.1 is the last version from this artifact i guess.)

  3. In your activity, use like this syntax

    Import this class :

    import androidx.lifecycle.ViewModelProviders; for AndroidX

    import android.arch.lifecycle.ViewModelProviders; when using Pre-AndroidX

    And obtain your ViewModel like following

    ViewModelProviders.of(this).get(ProfileObservableViewModel::class.java) // Kotlin syntax

    ---- or ----

    ViewModelProviders.of(this).get(ProfileObservableViewModel.class); // Java syntax

Appease answered 22/1, 2019 at 17:48 Comment(2)
Happy to help :)Appease
ViewModelProviders is in extensions, see Ricardo Costeira's answer.Statuesque
D
4

Paste the code below in build.gradle(:app)

implementation 'androidx.fragment:fragment-ktx:1.4.1'
Dosser answered 26/4, 2022 at 8:20 Comment(0)
C
1

paste the following or similar(relevant to your settings) in app.gradle under dependencies

implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.5'
Cannery answered 15/9, 2021 at 13:14 Comment(0)
U
1

I add the last version of this dependency from https://developer.android.com/kotlin/ktx/extensions-list

implementation "androidx.activity:activity-ktx:1.4.0"

Untwine answered 28/5, 2022 at 10:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.