java.lang.InstantiationException <com.example.MyViewModel> 使用 SavedStateViewModelFactory 时没有零参数构造函数

java.lang.InstantiationException <com.example.MyViewModel> has no zero argument constructor when use SavedStateViewModelFactory

我只是尝试按照本指南了解 MVVM 架构:https://developer.android.com/jetpack/guide

我的问题:当我在我的 ViewModel class“SavedStateHangle”和“UserRepository”中使用两个参数时,我的应用程序崩溃并出现此错误:

E/AndroidRuntime: at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78) at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1955) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:214) at android.app.ActivityThread.main(ActivityThread.java:7058) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965) Caused by: java.lang.InstantiationException: java.lang.Class<ru.itschool.jetpackguide.UserProfileViewModel> has no zero argument constructor at java.lang.Class.newInstance(Native Method) at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:219)

如果我从构造函数参数中删除 UserRepository(并且构造函数只有 SavedStateHandle),则片段可以工作(没有 UserRepository,但它不会因该错误而崩溃)。

我将我的 ViewModel 与 SavedStateViewModelFactory 和 Hilt + Dagger 库一起使用,就像 Android 应用程序架构指南中那样。

我正在通过 UserProfileFragment 上的这段代码创建我的 ViewModel:

private val viewModel : UserProfileViewModel
    by viewModels(
        factoryProducer = {SavedStateViewModelFactory(activity?.application, this, defaultBundle())}
)

和我的 ViewModel 代码:

@HiltViewModel
class UserProfileViewModel @Inject constructor(
    savedStateHandle: SavedStateHandle,
    userRepository: UserRepository
) : ViewModel() {
    var userId: String = savedStateHandle["uid"]
            ?: throw IllegalArgumentException("Missing user ID")
    private val _user = MutableLiveData<User>()
    val user : LiveData<User> = _user

    init {
        viewModelScope.launch {
            _user.value = userRepository.getUser(userId)
        }
    }
}

您可以找到我项目的完整代码here。 也许有人在我之前实施了本指南并且已经知道答案? :)

当您为 ViewModel 提供工厂时,您就在为 viewModels 提供一种创建 ViewModel 实例的方法(如果它尚不存在)。 SavedStateViewModelFactory 只提供了一种用 SavedStateHandle 实例化 ViewModel 的方法,它显然不知道如何在您不做任何工作的情况下提供您的自定义存储库。

因此,为了给它提供所需的帮助,您可能应该考虑创建 ViewModelProvider.Factory 的自定义实现,这需要您实现 create 方法:

class VMF: ViewModelProvider.Factory {

    override fun <T : ViewModel?> create(modelClass: Class<T>): T {}
}

对于您的示例,假设您希望 ViewModel 中可用的片段参数,一个简化的实现将是:

class VMF(private val userRepository: UserRepository, private val args: Bundle?): ViewModelProvider.Factory {

    override fun <T : ViewModel?> create(modelClass: Class<T>): T {

        if(UserProfileViewModel::class.java.isAssignableFrom(modelClass)) {

            return UserProfileViewModel(userRepository, args)
        }
        ...
    }
}

然后您将使用您的工厂代替默认工厂:

private val viewModel : UserProfileViewModel by viewModels {
    VMF(userRepository, arguments)
}