简体   繁体   English

无法创建 class ViewModel 的实例

[英]Cannot create an instance of class ViewModel

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.我正在尝试使用 Android 架构组件编写一个示例应用程序,但即使尝试了几天我也无法让它工作。 It gives me the above exception.它给了我上述例外。

Lifecycle owner:-生命周期所有者:-

public class MainActivity extends LifecycleActivity {

    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView textView = findViewById(R.id.tv_user);
        PostViewModel viewModel = ViewModelProviders.of(this).get(PostViewModel.class);
        viewModel.loadPosts();
        viewModel.getPost().observe(this, new Observer<Post>() {
            @Override
            public void onChanged(@Nullable Post post) {
                if(post != null) {
                    textView.setText(post.toString());
                }
            }
        });
    }
}

ViewModel:-视图模型:-

public class PostViewModel extends ViewModel {
    private MediatorLiveData<Post> post;
    private PostRepository postRepo;

    PostViewModel() {
        post = new MediatorLiveData<>();
        postRepo = new PostRepository();
    }

    public LiveData<Post> loadPosts() {
        post.addSource(postRepo.getPost(),
                post -> this.post.setValue(post)
        );
        return post;
    }

    @NonNull
    public LiveData<Post> getPost() {
        return post;
    }
}

如果您使用的是Hilt ,请确保您的活动/片段具有@AndroidEntryPoint注释

将您的构造函数public

Make sure your ViewModel has constructor with only one parameter ie Application . 确保ViewModel构造函数只有一个参数,即Application

example: 例:

public YourViewModel(Application application) {
    super(application);
    ...

I had this problem following google's roomdb CodeLab .我在 google 的roomdb CodeLab之后遇到了这个问题。 Solution was changing the following.解决方案是更改以下内容。

Edited已编辑

Add the following Build dependencies to Gradle file (as of 2/22/2020)将以下构建依赖项添加到 Gradle 文件(截至 2/22/2020)

implementation 'androidx.fragment:fragment:1.2.2'
implementation 'androidx.lifecycle:lifecycle-process:2.2.0'
implementation 'androidx.lifecycle:lifecycle-service:2.2.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-savedstate:2.2.0'
annotationProcessor 'androidx.lifecycle:lifecycle-compiler:2.2.0'

Imports within the fragment片段内的导入

import androidx.lifecycle.ViewModelProvider;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;

Creating the viewModel.创建视图模型。 Add one of the following methods.添加以下方法之一。

Note : I'v seen this done many ways.注意:我见过很多方法。 I believe the correct way is using getDefaultViewModelProviderFactory() .我相信正确的方法是使用getDefaultViewModelProviderFactory() But I have been using requireActivity() .但我一直在使用requireActivity()

 new ViewModelProvider(requireActivity(),getDefaultViewModelProviderFactory()).get(YourViewModel.class);

| |

 new ViewModelProvider(requireActivity()).get(YourViewModel.class);

          

ViewModelProvider Docs ViewModelProvider 文档

Deprecated已弃用

implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0-rc01'
annotationProcessor 'androidx.lifecycle:lifecycle-compiler:2.2.0-rc01'

If you are using Kotlin make sure to replace any annotationProcessor in build.gradle with kapt . 如果您使用的Kotlin确保更换任何annotationProcessorbuild.gradlekapt

Like: 喜欢:

annotationProcessor "android.arch.persistence.room:compiler:$rootProject.roomVersion"

Will become 会变成

kapt "android.arch.persistence.room:compiler:$rootProject.roomVersion"

and add 并添加

apply plugin: 'kotlin-kapt' on top of the buidl.gradle file. buidl.gradle文件顶部apply plugin: 'kotlin-kapt'

Annotation Processing with Kotlin 使用Kotlin进行注释处理

DggerHilt也可能是原因,如果您正在使用它,请确保您的activity/fragment上有@AndroidEntryPoint注释。

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. 我的构造函数来自Android Developer示例,并且包含Repository作为参数。 Creating an additional constructor that was empty with no params and having it public solved the issue. 创建一个没有参数且为空的附加构造函数并将其公开解决了该问题。

ie, in your case 即,在您的情况下

public PostViewModel() {}

For people using Jetpack Compose, Navigation and Hilt对于使用 Jetpack Compose、Navigation 和 Hilt 的人

Make sure to use the hiltNavGraphViewModel instead of viewModel .确保使用hiltNavGraphViewModel而不是viewModel

This is provided by androidx.hilt:hilt-navigation-compose dependency.这是由androidx.hilt:hilt-navigation-compose依赖项提供的。

More details in the docs . 文档中的更多详细信息。

公开类和构造器可以解决我的问题。

There are few reason to throw the exception . 没有什么理由抛出异常。 I have mention some of them.. 我提到了其中一些。

  1. Make sure your view Model class is public 确保您的视图模型类是公共的
  2. Make sure your view model class constructor is public 确保您的视图模型类构造函数是公共的

  3. Make sure you have added the dependency in your gridle file for lifecycle also if you use room and other libries you have added .. 如果您使用房间和其他已添加的库,请确保已在生命周期的网格文件中添加了依赖项。

  4. if you create object any other dependent class in your view model class constructor . 如果创建对象,则在视图模型类构造函数中创建其他任何依赖类。 Other class can throw error to create the instance of viewModel 其他类可能引发错误以创建viewModel的实例

If you used viewmodel inside your activity check that your activity extends "DaggerAppCompatActivity" or not 如果您在活动中使用了viewmodel,请检查您的活动是否扩展了“ DaggerAppCompatActivity”

For instance 例如

public class UserComments extends AppCompatActivity 

change this to 更改为

public class UserComments extends DaggerAppCompatActivity

If you are using Hilt then don't forget to add these four dependencies.如果您正在使用 Hilt,请不要忘记添加这四个依赖项。

    implementation "com.google.dagger:hilt-android:2.28-alpha"
    kapt "com.google.dagger:hilt-android-compiler:2.28-alpha"
    implementation 'androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha01'
    kapt "androidx.hilt:hilt-compiler:1.0.0-alpha01"

Note:- If any of these dependencies are missing you will get Cannot create an instance of class ViewModel error注意:- 如果缺少这些依赖项中的任何一个,您将收到Cannot create an instance of class ViewModel错误

  1. Mostly, Solution is making Class and Constructor Public as the other answers 通常,解决方案是将类和构造函数公开为其他答案
  2. It may also be a runtime error, check the Logcat Error Logs if there are multiple causes listed. 这也可能是运行时错误,如果列出了多个原因,请检查Logcat错误日志。

Please add below code.请添加以下代码。 It worked for me它对我有用

val binding = FragmentLayoutBinding.inflate(inflater, container, false)

val viewModel = ViewModelProvider(
            requireActivity(),
            defaultViewModelProviderFactory
            ).get(MainViewModel::class.java)

在 viewModel 之上添加 @HiltViewModel 。

I got this after migrating to AndroidX. 迁移到AndroidX后,我得到了这个。

There's a bug in androidx.lifecycle:lifecycle-viewmodel:2.0.0-beta01 where Proguard removes the constructor. androidx.lifecycle:lifecycle-viewmodel:2.0.0-beta01中存在一个错误,其中Proguard会删除该构造函数。

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

Fix by upgrading to 2.0.0, and remember to update your proguard rules if needed. 通过升级到2.0.0进行修复,并记住在需要时更新您的proguard规则。

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)

Extend AndroidViewModel from your ViewModel class. 从ViewModel类扩展AndroidViewModel

public class YourViewModel extends AndroidViewModel {

    public YourViewModel(Application application) {
        super(application);

        //Todo: ...
    }

}

如果您的PostViewModel类是内部类,请确保其公共和静态

In my case, it was gradle a dependencies problem.就我而言,它是 gradle 依赖关系问题。

If you are using Livedata,,如果您使用的是 Livedata,

build.gradle(Module.app) build.gradle(Module.app)

not不是

implementation 'android.arch.lifecycle:extensions:1.1.1'
kapt 'android.arch.lifecycle:common-java8:1.1.1'

use these使用这些

implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
kapt 'androidx.lifecycle:lifecycle-common-java8:2.2.0'

If you're using Hilt Dependency Injection, You probably have missed @ViewModelInject .如果您正在使用 Hilt 依赖注入,您可能已经错过了@ViewModelInject Because, Hilt provide its own injection for viewmodel.因为,Hilt 为视图模型提供了自己的注入。

In my case, I used and @Inject due to this caught into the error.就我而言,我使用了 @Inject ,因为这陷入了错误。

如果您在 Kotlin Dagger Hilt 中遇到此问题,即使在 @HiltViewModel 并使用 @Inject 之后,请确保您已更新所有刀柄依赖项。

I'm using this example android-arcuitecture-component BasicSample to make a new project, facing a similar error log, found I did'n change de applicatio name 我正在使用此示例android-arcuitecture-component BasicSample制作一个新项目,面临类似的错误日志,发现我没有更改应用名称

AndroidManifest.xml AndroidManifest.xml

and that was my error, to fix put the aplicacion name to de BasicApp, this class is implement in the example. 那是我的错误,要修复将aplicacion名称放到de BasicApp中,该类在示例中实现。

...
<application
    android:name=".BasicApp"
    android:allowBackup="false"

就我而言,我需要使用ListItemViewModelFactory将参数传递给我的视图模型。

创建一个没有参数且为空的附加构造函数并将其公开解决了该问题。

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. 以我为例,原因是我试图在创建活动之前不久将片段中ViewModel的共享实例获取。 That happens when application is restoring its state after being killed. 当应用程序被杀死后恢复其状态时,会发生这种情况。

Preconditions : 前提条件

  1. My ViewModel has a public constructor. 我的ViewModel有一个公共构造函数。
  2. My ViewModel has multiple arguments. 我的ViewModel有多个参数。 But this is absolutely fine as I use ViewModelFactory to construct the ViewModel. 但这绝对好,因为我使用ViewModelFactory构造ViewModel。
  3. My Fragment and Activity shares the same instance of the ViewModel . 我的Fragment和Activity 共享相同的ViewModel实例 Other words: Activity creates the ViewModel and fragment receives the same instance later. 换句话说:Activity创建ViewModel,并且片段稍后接收相同的实例。

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; 当我第一次打开应用程序时,一切正常:活动创建ViewModel实例; I open Fragment, which get the instance of ViewModel. 我打开Fragment,它获取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. 但是,当应用程序被杀死后试图恢复其状态时,它首先调用Fragment的onCreate主体,然后调用Activity的onCreate主体。 At that point fragment can't get the ViewModel as Activity had not created it yet. 此时,片段无法获取ViewModel,因为Activity尚未创建它。

Solution 1 : Move the code when fragment get the ViewModel from onCreate to onViewCreated. 解决方案1 :当片段将ViewModel从onCreate移到onViewCreated时,移动代码。 Which is fine as I observe all liveDatas in onViewCreated as well. 就像我在onViewCreated中观察所有liveData一样,这很好。

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. 解决方案2 :在调用super.onCreate之前,在Activity.onCreate中创建ViewModel的实例。 In this case you can get the ViewModel in your fragment's onCreate . 在这种情况下,您可以在片段的onCreate中获取ViewModel。

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 ")
}

我的问题是 IDE 向我的 ViewModel 类添加了一个“抽象”修饰符。

公开ViewModal 类和构造

If constructor of your viewmodel is public and accepts only application then make sure you can create your own model without ViewModelProvider .如果您的视图模型的构造函数是公共的并且只接受应用程序,那么请确保您可以在没有ViewModelProvider情况下创建自己的模型。 Error message might be much more clear:错误信息可能更清楚:

val model = YouViewModel(app)

I'm a proficient Android developer and I have used ViewModel 100s of times with no issue.我是一名熟练的 Android 开发人员,我已经使用 ViewModel 100 次了,没有任何问题。 Today I came across this issue.今天我遇到了这个问题。 Spent hours and scrolled through various SO posts.花了几个小时滚动浏览各种 SO 帖子。 Didn't get solved.没有得到解决。

Then I saw that the package name in which I have the ViewModel contains new .然后我看到我拥有 ViewModel 的包名称包含new Like this:像这样:

com.myapp.myfeature.new.feature

I changed new to neww for testing like this: com.myapp.myfeature.neww.feature我换了newneww测试是这样的: com.myapp.myfeature.neww.feature

and it worked!它奏效了! I hope someone find it useful.我希望有人觉得它有用。

If you are using version 2.33-beta and upper remove these dependencies;如果您使用的是 2.33-beta 和 upper 版本,请删除这些依赖项;

implementation "androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha03"
kapt "androidx.hilt:hilt-compiler:1.0.0-beta01"

Keep only these two dependency只保留这两个依赖

implementation "com.google.dagger:hilt-android:2.33-beta"
kapt "com.google.dagger:hilt-android-compiler:2.33-beta"

For ViewModels used with Jetpack Compose对于与 Jetpack Compose 一起使用的 ViewModel


In case you are using Jepack Compose with a ViewModel in your component .如果您在组件中使用带有ViewModel Jepack Compose。 The @Preview annotation may cause this error. @Preview注释可能会导致此错误。 That was the problem in my case.这就是我的问题。

Hope it helps someone!希望它可以帮助某人!

I fixed the same problem by doing this.我通过这样做解决了同样的问题。

Note:- I am using Dagger hilt, Room database, MVVM, Data binding注意:-我正在使用 Dagger hilt、Room 数据库、MVVM、数据绑定

Added the annotation.添加了注释。

class AlertViewModel
@Inject
constructor(private val userRepository: AlertRepository) : ViewModel(){
    val getList:LiveData<List<Alert>> get() =
        userRepository.getList.flowOn(Dispatchers.Main)
            .asLiveData(context = viewModelScope.coroutineContext)

    fun insert(user:Alert){
        viewModelScope.launch {
            userRepository.insert(user)
        }
    }
}

To

@HiltViewModel // Added this annotation
class AlertViewModel
@Inject
constructor(private val userRepository: AlertRepository) : ViewModel(){
    val getList:LiveData<List<Alert>> get() =
        userRepository.getList.flowOn(Dispatchers.Main)
            .asLiveData(context = viewModelScope.coroutineContext)

    fun insert(user:Alert){
        viewModelScope.launch {
            userRepository.insert(user)
        }
    }
}

I had a different scenario when creating a view model instance:创建视图模型实例时,我遇到了不同的情况:

  1. I was requesting for the instance in a fragment.我正在请求片段中的实例。<\/li>
  2. My ViewModel required a parameter to be passed on the constructor.我的 ViewModel 需要在构造函数上传递一个参数。<\/li>
  3. I was not using Dependency Injection.我没有使用依赖注入。<\/li><\/ol>

    Solution In a scenario where your viewmodel requires a parameter to be passed you have to create a ViewModelFactory to define your instances解决方案在您的视图模型需要传递参数的情况下,您必须创建一个 ViewModelFactory 来定义您的实例

    Solution In Practice实践中的解决方案

    - ViewModel Sample class SharedViewModel(private val repository: UserRepository) : ViewModel() { init { viewModelScope.launch { repository.refreshDataInDb() } } } - Creating ViewModel Factory class ViewModelFactory( private val repository: UserRepository ) : ViewModelProvider.NewInstanceFactory(){ override fun <T : ViewModel> create(modelClass: Class<T>): T { return SharedViewModel( repository as UserRepository) as T } } - Creating ViewModel Instannce in a Fragment private lateinit var factory: ViewModelFactory private lateinit var searchViewModel: SharedViewModel private lateinit var repository: UserRepository repository = UserRepository() factory = ViewModelFactory(repository) searchViewModel = ViewModelProvider(requireActivity(), factory)[SharedViewModel::class.java]<\/code><\/pre>"

Well this will fix the issue for sure好吧,这肯定会解决问题

First of all make sure you have this dependency首先确保你有这个依赖

//Room DB
implementation "androidx.room:room-runtime:2.2.5"
annotationProcessor 'android.arch.persistence.room:compiler:1.1.1'

Then remove viewmodel constructor, then create init function as your constructor然后删除 viewmodel 构造函数,然后创建 init function 作为您的构造函数

 public void init(Application application){
        instance = new FirebaseDatabaseInstance();
        databaseRepository = new DatabaseRepository(application);
        allChatMembers = databaseRepository.getAllChatMembers();
    }

Then this will solve...那么这将解决...

Not for OP's case, but adding it here for newcomers.不是针对 OP 的情况,而是在此处为新手添加它。

If you inherit from AndroidViewModel and there is some heavy work in the main Thread (like accessing the database) it'll wrongly throw this error.如果你从AndroidViewModel继承并且在主线程中有一些繁重的工作(比如访问数据库),它会错误地抛出这个错误。

After I switched to inherit from ViewModel , it showed the correct error and I could move the heavy work to Dispatchers.IO .在我切换到从ViewModel继承后,它显示了正确的错误,我可以将繁重的工作移至Dispatchers.IO After moving UI blocking stuff to Dispatchers.IO , I re-tested using AndroidViewModel and everything works fine again.将 UI 阻塞内容移至Dispatchers.IO后,我使用AndroidViewModel重新测试,一切正常。

Conclusion: "UI blocking work on the main thread when inheriting from AndroidViewModel can throw this error".结论:“从AndroidViewModel继承时,主线程上的 UI 阻塞工作可能会引发此错误”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM