【问题标题】:java.lang.RuntimeException: Cannot create an instance of class ViewModeljava.lang.RuntimeException:无法创建类 ViewModel 的实例
【发布时间】:2020-08-19 11:20:05
【问题描述】:

我正在尝试实例化一个 viewModel 类,该类包含一个 init 块,我正在尝试通过 volley 发送 Get 请求。问题是当我试图在我的 Fragment 类中实例化这个类时,我收到了这个错误,我不知道为什么。也许来自构造函数的上下文会是问题?谢谢:

ViewModel 类

class BooksFragmentViewModel(c : Context) : ViewModel() {

lateinit var cont: Context
var books: MutableLiveData<MutableList<BookItem>> = MutableLiveData<MutableList<BookItem>>()
var triggerAddBook = MutableLiveData<Boolean>()
var triggerDeleteBook = MutableLiveData<Boolean>()
var triggerEditBook = MutableLiveData<Boolean>()
var bookRepo: BookRepository = BookRepository()
var bookItemAdd: BookItem? = null
var bookItemDelete: BookItem? = null
var bookItemEdit : BookItem? = null
var bookNew: LiveData<BookItem> = Transformations.switchMap(triggerAddBook) {
    if (it != null && it)
        addBook()
    else
        null
}

  init {
        books = bookRepo.booksGetRequest(c)
    }

片段类

class BooksFragment : Fragment(), BooksAdapter.OnDeleteBtnClicked, BooksAdapter.OnEditBtnClicked {
lateinit var booksModel: BooksFragmentViewModel
var position: Int = 0

private var adapter: BooksAdapter = BooksAdapter(this, this)
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                          savedInstanceState: Bundle?): View? {
    return inflater.inflate(R.layout.fragment_books, container, false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    booksModel = ViewModelProvider(requireActivity()).get(BooksFragmentViewModel::class.java)
    booksLoading_progressBar.visibility = View.VISIBLE
    var c: Context? = context
    if (c != null) {
        booksModel.setContext(c)
    }

【问题讨论】:

  • 您忘记添加 Viewmodel 工厂了吗?
  • 我应该怎么做?谢谢@MohamedAbdelraZek
  • 好的,我会发布答案以明确

标签: kotlin mvvm viewmodel


【解决方案1】:

问题确实是因为带有参数的主构造函数。您要求ViewModelProvider 创建BooksFragmentViewModel 类的实例,但提供者对预期参数一无所知。

Here is a post 关于该主题。

如何解决这个问题?

  1. 尽可能去掉所有主要的构造函数参数。这应该是最简单的方法;
  2. 创建ViewModelProvider.Factory,它将处理您的视图模型的创建。

第一个选项很清楚,但是对于第二个选项,您应该执行以下操作。

创建ViewModelProvider.Factory:

class BooksFragmentViewModelFactory (val context: Context) :
    ViewModelProvider.Factory {

    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(BooksFragmentViewModel::class.java)) {
            return BooksFragmentViewModel(context) as T
        } else {
            throw RuntimeException("Failed to create instance of the ${modelClass.simpleName}")
        }
    }
}

使用工厂ViewModelProvider:

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        val bookViewModelFactory = BooksFragmentViewModelFactory(requireContext())
        booksModel = ViewModelProvider(requireActivity(), bookViewModelFactory).get(BooksFragmentViewModel::class.java)
        booksLoading_progressBar.visibility = View.VISIBLE
    }

更多解释请查看codelab from Google (step 8)。有足够的示例来了解如何使用视图模型工厂的基础知识。

【讨论】:

  • 非常感谢!这是解决我问题的解决方案!
【解决方案2】:

如果您有带参数的ViewModel(如示例中的上下文),那么您需要使用Factory 将任何参数传递给ViewModel

 booksModel = ViewModelProvider(this,object :
        ViewModelProvider.Factory{
        override fun <T : ViewModel?> create(modelClass: Class<T>): T {
            return booksModel(requireActivity()) as T
        }
    }).get(booksModel::class.java)

【讨论】:

  • activity?.application!! 可以替换为 activity! 甚至更好 - requireContext()requireActivity()
  • 您可以传递与您将在 ViewModel 中执行的操作相关的任何上下文
  • 我只是指出了获取上下文的更简洁明了的方法。
  • 顺便说一句,您的代码似乎缺少某些东西,我可以确定 ViewModelProviders 已被弃用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-01-11
  • 2020-03-30
  • 2021-11-28
  • 2017-12-13
相关资源
最近更新 更多