无法创建 class ViewModel 的实例

Cannot create an instance of class ViewModel

我正在尝试使用 Android 架构组件编写一个示例应用程序,但即使在尝试了几天之后我也无法让它工作。它给了我上述异常。

生命周期所有者:-

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());
                }
            }
        });
    }
}

视图模型:-

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;
    }
}

构造你的构造函数public.

这对我来说不是很明显,但是当我收到这个错误时,我通过创建一个 public 构造函数解决了它。我的构造函数派生自 Android Developer 示例,并包含存储库作为参数。创建一个没有参数的空的附加构造函数并让它 public 解决了这个问题。

也就是说,在你的情况下

public PostViewModel() {}

制作 class 和构造函数 public 它解决了我的问题。

确保您的 ViewModel 构造函数只有一个参数,即 Application.

示例:

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

如果您使用的是 Kotlin,请确保将 build.gradle 中的任何 annotationProcessor 替换为 kapt

喜欢:

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

会变成

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

并添加

apply plugin: 'kotlin-kapt'buidl.gradle 文件之上。

Annotation Processing with Kotlin

几乎没有理由抛出异常。我已经提到了其中的一些..

  1. 确保您的视图模型 class 是 public

  2. 确保您的视图模型 class 构造函数是 public

  3. 确保您已在 gradle 文件中添加依赖项 如果您使用房间和您添加的其他库,生命周期也一样..

  4. 如果您在视图模型中创建对象任何其他依赖 class class 构造函数。其他 class 可以抛出错误来创建 视图模型实例

  1. 大多数情况下,Solution 将 Class 和 Constructor Public 作为其他答案
  2. 也可能是运行时错误,如果列出了多种原因,请检查 Logcat 错误日志。

迁移到 AndroidX 后我得到了这个。

androidx.lifecycle:lifecycle-viewmodel:2.0.0-beta01 中存在错误,Proguard 删除了构造函数。

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

通过升级到 2.0.0 进行修复,并记得在需要时更新您的混淆器规则。

我的错误信息是这样的:

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)

从您的 ViewModel class.

扩展 AndroidViewModel
public class YourViewModel extends AndroidViewModel {

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

        //Todo: ...
    }

}

如果您在 activity 中使用了视图模型,请检查您的 activity 是否扩展了 "DaggerAppCompatActivity"

例如

public class UserComments extends AppCompatActivity 

将此更改为

public class UserComments extends DaggerAppCompatActivity

我正在使用这个例子android-arcuitecture-component BasicSample做一个新项目,遇到类似的错误日志,发现我没有更改应用程序名称

AndroidManifest.xml

那是我的错误,为了修复将应用程序名称设置为 de BasicApp,此 class 在示例中实现。

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

如果您的 PostViewModel class 是内部 class,请确保它的 public 和静态

在我的例子中,我需要使用 ListItemViewModelFactory 将参数传递给我的视图模型。

就我而言,原因是我试图过早地在我的片段中获取 ViewModel 的共享实例 - 在 activity 创建之前。当应用程序被杀死后恢复其状态时会发生什么。

先决条件:

  1. 我的 ViewModel 有一个 public 构造函数。
  2. 我的 ViewModel 有多个参数。但这绝对没问题,因为我使用 ViewModelFactory 来构建 ViewModel。
  3. 我的片段和 Activity shares the same instance of the ViewModel。换句话说:Activity 创建 ViewModel 并且片段稍后接收相同的实例。

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]
}

片段中的代码:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    //fragment receives the instance of MapViewModel
    viewModel = ViewModelProviders.of(activity!!)[MapViewModel::class.java]
    ...
}

当我第一次打开应用程序时,一切正常:activity 创建了一个 ViewModel 实例;我打开 Fragment,它获取 ViewModel 的实例。但是当应用程序在被杀死后试图恢复它的状态时,它首先调用了 Fragment 的 onCreate 主体,然后是 Activity 的 onCreate 主体。那时,片段无法获取 ViewModel,因为 Activity 尚未创建它。

方案一:将fragment获取ViewModel时的代码从onCreate移到onViewCreated。这很好,因为我也观察了 onViewCreated 中的所有实时数据。

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

解决方案 2: 在调用 super.onCreate 之前,在 Activity.onCreate 中创建 ViewModel 的实例。在这种情况下,您可以在片段的 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 ")
}

解决方案 3:

如果您在 ViewModel 中注入存储库实例,请检查您是否使用 @Inject constructor(...): ViewModel() 注入存储库,而是 **@ViewModelInject constructor(...): ViewModel()**

我在 google 的 roomdb CodeLab 之后遇到了这个问题。解决方案正在更改以下内容。

已编辑

将以下构建依赖项添加到 Gradle 文件(截至 2020 年 2 月 22 日)

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'

片段内导入

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

正在创建视图模型。添加以下方法之一。

注意:我见过很多方法。我相信正确的方法是使用 getDefaultViewModelProviderFactory()。但是我一直在用requireActivity().

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

|

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

          

ViewModelProvider Docs

Deprecated

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

我的问题是 IDE 向我的 ViewModel class.

添加了一个“abstract”修饰符

就我而言,这是 gradle 依赖关系问题。

如果您使用的是实时数据,

build.gradle(Module.app)

没有

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

使用这些

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

制作ViewModel class并构造public

如果您的视图模型的构造函数是 public 并且只接受应用程序,那么请确保您可以在没有 ViewModelProvider 的情况下创建自己的模型。错误信息可能更清楚:

val model = YouViewModel(app)

如果您使用的是 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"

注意:- 如果缺少任何这些依赖项,您将收到 Cannot create an instance of class ViewModel 错误

请添加以下代码。它对我有用

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

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

如果您使用的是 Hilt,请确保您的 activity/fragment 具有 @AndroidEntryPoint 注释

我是一名熟练的 Android 开发人员,我已经使用 ViewModel 100 多次,没有任何问题。今天我遇到了这个问题。花了几个小时浏览了各种 SO 帖子。没解决。

然后我看到我有ViewModel的包名包含new。像这样:

com.myapp.myfeature.new.feature

我将 new 更改为 neww 以进行如下测试: com.myapp.myfeature.neww.feature

成功了!我希望有人觉得它有用。

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

如果您正在使用 Hilt 依赖注入,您可能错过了 @ViewModelInject。因为,Hilt 为视图模型提供了自己的注入。

在我的例子中,我使用了@Inject,因为它陷入了错误。

如果您使用的是 2.33-beta 及更高版本,请删除这些依赖项;

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

只保留这两个依赖

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

对于使用 Jetpack Compose、Navigation 和 Hilt 的用户

确保使用 hiltNavGraphViewModel 而不是 viewModel

这是由 androidx.hilt:hilt-navigation-compose 依赖项提供的。

docs 中有更多详细信息。

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

在您的 viewModel 之上添加 @HiltViewModel 。

对于与 Jetpack Compose 一起使用的 ViewModels


如果您在 组件 中使用带有 ViewModel 的 Jepack Compose。 @Preview 注释可能会导致此错误。这就是我的问题。

希望对大家有所帮助!

我通过这样做解决了同样的问题。

注意:- 我正在使用 Dagger 刀柄、Room 数据库、MVVM、数据绑定

添加了注释。

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

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

我在创建视图模型实例时遇到了不同的情况:

  1. 我在片段中请求实例。
  2. 我的 ViewModel 需要在构造函数上传递一个参数。
  3. 我没有使用依赖注入。

解决方案 在您的视图模型需要传递参数的情况下,您必须创建一个 ViewModelFactory 来定义您的实例

实践中的解决方案

- 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]

嗯,这肯定会解决问题

首先确保你有这个依赖

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

然后删除 viewmodel 构造函数,然后创建 init 函数作为您的构造函数

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

那么这就解决了...