Cannot create an instance of class ViewModel

后端 未结 23 2432
[愿得一人]
[愿得一人] 2020-12-05 12:37

I am trying to write a sample app using Android architecture components and but even after trying for days I could not get it to work. It gives me the above exception.

相关标签:
23条回答
  • 2020-12-05 13:17

    I got this after migrating to AndroidX.

    There's a bug in androidx.lifecycle:lifecycle-viewmodel:2.0.0-beta01 where Proguard removes the constructor.

    https://issuetracker.google.com/issues/112230489

    Fix by upgrading to 2.0.0, and remember to update your proguard rules if needed.

    My error message looked like this:

    java.lang.RuntimeException: Cannot create an instance of class my.custom.viewmodel.CustomViewModel
    at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:202)
    at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:135)
    at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:103)
    ......
    Caused by: java.lang.NoSuchMethodException: <init> [class android.app.Application]
    at java.lang.Class.getConstructor0(Class.java:2204)
    at java.lang.Class.getConstructor(Class.java:1683)
    at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:200)
    ... 34 more
    
    
      androidx.test.espresso.PerformException: Error performing 'single click - At Coordinates: 539, 1167 and precision: 16, 16' on view 'with id: my.test:id/button_return_to_main_menu'.
    at androidx.test.espresso.PerformException$Builder.build(PerformException.java:82)
    at androidx.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(DefaultFailureHandler.java:79)
    .....
    Caused by: java.lang.RuntimeException: Unable to start activity ComponentInfo{my.custom.domain.MainActivity}: java.lang.RuntimeException: Cannot create an instance of class my.custom.viewmodel.CustomViewModel
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2646)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707)
    
    0 讨论(0)
  • 2020-12-05 13:19

    In my case I needed to use a ListItemViewModelFactory to pass in a parameter to my view model.

    0 讨论(0)
  • 2020-12-05 13:21

    It was not completely obvious to me, but when getting this error I resolved it by creating a public constructor. My constructor was derived from the Android Developer examples and contained the Repository as a parameter. Creating an additional constructor that was empty with no params and having it public solved the issue.

    i.e., in your case

    public PostViewModel() {}

    0 讨论(0)
  • 2020-12-05 13:22

    if you are using Hilt, ensure your activity/fragment is having @AndroidEntryPoint annotation

    0 讨论(0)
  • 2020-12-05 13:22

    In my case the reason was that I was trying to get shared instance of the ViewModel in my fragment to soon - before the activity was created. That happens when application is restoring its state after being killed.

    Preconditions:

    1. My ViewModel has a public constructor.
    2. My ViewModel has multiple arguments. But this is absolutely fine as I use ViewModelFactory to construct the ViewModel.
    3. My Fragment and Activity shares the same instance of the ViewModel. Other words: Activity creates the ViewModel and fragment receives the same instance later.

    Code in activity:

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        //factory is constructed using Dagger
        val factory = App.get().components().appComponent.getMapViewModelFactory() 
        //activity creates the instance of MapViewModel
        viewModel = ViewModelProviders.of(this, factory)[MapViewModel::class.java]
    }
    

    Code in fragment:

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        //fragment receives the instance of MapViewModel
        viewModel = ViewModelProviders.of(activity!!)[MapViewModel::class.java]
        ...
    }
    

    When I open the app for the first time, everything works fine: activity creates instance of ViewModel; I open Fragment, which get the instance of ViewModel. But when when application is trying to restore its state after being killed, first it calls the body of onCreate of the Fragment and then the body of onCreate of the Activity. At that point fragment can't get the ViewModel as Activity had not created it yet.

    Solution 1: Move the code when fragment get the ViewModel from onCreate to onViewCreated. Which is fine as I observe all liveDatas in onViewCreated as well.

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
    
        viewModel = activity?.run { ViewModelProviders.of(this)[MapViewModel::class.java] } ?: throw Exception("Invalid Activity")
    
        viewModel.getSurveyDateLiveData().observe(viewLifecycleOwner, Observer<String> { dateTextView.text = it })
        ...
    }
    

    Solution 2: Create the instance of ViewModel in Activity.onCreate before super.onCreate is called. In this case you can get the ViewModel in your fragment's onCreate.

    override fun onCreate(savedInstanceState: Bundle?) {
        
        val factory = App.get().components().appComponent.getMapViewModelFactory()
        viewModel = ViewModelProviders.of(this, factory)[MapViewModel::class.java]
        
        super.onCreate(savedInstanceState)
        Timber.d("cc: onCreate: $this ")
    }
    

    Solution 3:

    If you are injecting repository instance in your ViewModel, Check that you are not using @Inject constructor(...):ViewModel() to inject your repository, but rather **@ViewModelInject constructor(...):ViewModel()**

    0 讨论(0)
提交回复
热议问题