android - 由 : java. lang.RuntimeException : Cannot create an instance of class com. app.MyViewModel 引起

标签 android kotlin mvvm viewmodel android-viewmodel

我遇到了访问 View 模型的问题。

我有一个 Activity 和 2 个 fragment 。 我有一个用于 Activity 和 fragment 的 View 模型,使用在主机 Activity 中创建的相同 View 模型实例。

class MyViewModel(var paymentDataModel: PaymentDataModel) : ViewModel(){

   fun someMethod():Boolean{
   //return Something 
}
}

class MyViewModelFactory(var paymentDataModel: PaymentDataModel) : ViewModelProvider.Factory {

    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        return MyViewModel(paymentDataModel) as T
    }
}

class NewPaymentAmountFragment : Fragment() {
    private val paymentViewModel: MyViewModel by activityViewModels()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        if(paymentViewModel.someMehtod()){ 
   //Accessing activity viewmodel in fragment
     }
    }
}

如果我在 Activity 函数中使用 viewModel 扩展定义 viewmodel,它会显示以下错误。

Caused by: java.lang.RuntimeException: Cannot create an instance of class com.app.MyViewModel

    class MyActivity : BaseActivity(){
    
    val myViewModel: MyViewModel by viewModels { 
    MyViewModelFactory(constructPaymentDataModel()) }

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

但是,如果我使用 ViewModelProvider() 以正常方式定义 ViewModel,它就可以正常工作。

class MyActivity : BaseActivity(){

lateint var myViewModel: MyViewModel 

   override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val viewModelFactory = MyViewModelFactory(constructPaymentDataModel())
        myViewModel = ViewModelProvider(this, viewModelFactory)[MyViewModel::class.java]
    }
}

只有当首先访问 fragment 中的 viewmodel 时才会发生这种情况。

如果我在 oncreate of activity 之前访问过一次 activity 中的 viewmodel,则在 fragment 中它工作正常。它能够获取 View 模型实例。

class MyActivity : BaseActivity(){

val myViewModel: MyViewModel by viewModels { 
MyViewModelFactory(constructPaymentDataModel()) }

 override fun onCreate(savedInstanceState: Bundle?) {
        println(myViewModel.isPaymentMethodExists.value)
        super.onCreate(savedInstanceState)
}
}

在这里,我在 fragment 访问 Activity View 模型之前访问了 View 模型。 所以这里的viewmodel是在断点到这个println方法的时候被lazy赋值的。

相同,如果我首先访问 fragment 中的 View 模型。 Activity 中的惰性 View 模型未分配。

总结如下 如果使用 View 模型扩展在 Activity 和 fragment 中都定义了 View 模型,并且首先在 fragment 中访问 View 模型,则它不起作用。

最佳答案

当您访问 Fragment 中的 ViewModel 时,您没有通过工厂:

private val paymentViewModel: MyViewModel by activityViewModels()

您需要执行与 Activity 中相同的操作 - 如果需要,它们都需要能够构建 VM,因此代码相同:

// still using the activityViewModels delegate, because you want the Activity's VM instance
private val paymentViewModel: MyViewModel by activityViewModels {
    MyViewModelFactory(constructPaymentDataModel())
}

ViewModel 的工作方式是每个 ActivityFragment 类(如果您使用 Navigation library) 每个都可以有自己的 VM 实例。这允许相同 Activity 或任何东西的不同实例在被销毁后获取相同的 VM 对象 - VM 比它们长,并且它们共享它。

它还允许其他组件获取属于 Activity(或其他)的特定实例。这就是 Fragment 可以获取其父 Activity 的特定 VM 副本并彼此共享数据的方式,因为它们都在查看同一个实例。


要获得 VM,您调用 ViewModelProvider(owner)(其中 ownerActivityFragment拥有该实例)然后调用 get(SomeViewModel::class.java) 来说明您想要获取哪种类型的 VM。 如果已经有与该所有者关联的该 VM 的实例,它将返回它 - 这就是所有东西共享同一个 VM 对象的方式。

(by viewModelsby activityViewModels 只是很好的简写 - 它们只是调用 ViewModelProvider(this)viewModelProvider( parentActivity)分别传递相关的owner,获取需要的VM)

如果没有此 VM 的实例,则提供商将创建一个并将其存储以供其他任何请求它的实例使用这是关键部分 - 为特定所有者请求 VM 实例的第一件事是创建它的原因。如果该创建需要工厂(如您的情况),第一个请求需要提供该工厂

因此,当您的 Activity 是第一个请求 VM 时,它会提供用于创建它的工厂。然后当 Fragment 稍后发出请求时,它不提供工厂功能并不重要 - VM 实例已经存储。但是反过来做,你就会遇到问题。因为 Fragment 发出请求,但不提供工厂,它会尝试使用默认的无参数工厂。这对带有 PaymentDataModel 参数的 VM 类不起作用,因此您会收到错误消息。在您请求 VM 的任何地方提供工厂,它就会工作。

希望一切顺利!

关于android - 由 : java. lang.RuntimeException : Cannot create an instance of class com. app.MyViewModel 引起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74548705/

相关文章:

android - Navigation.findNavController()无法找到 View

android - 我可以在伴生对象中共享 ViewModel 吗?

c# - 如何在 ListView 中从 ViewModel 调用命令,其中 ItemsSource 是其他模型类

android - 在我的手机上运行的网络安全策略不允许 CLEARTEXT 通信

java - Google Plus Api 运行时异常

unit-testing - Kotlin-multiplatform:如何执行 iOS 单元测试

java - 如何检测坐标是否在区域内?

c# - 对我的模型上的属性实现 IsDirty (WPF MVVM)

使用 unicode 的 java 客户端和 C# 服务器

android - request.setTesting(false) 时 admob 广告不显示