You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

创建ToDoViewModel实例失败致App崩溃,求原因及解决方案

Android TodoApp ViewModel创建崩溃问题排查

问题描述

开发简易TodoApp时,创建ToDoViewModel实例导致App崩溃,触发Cannot create an instance of class com.ma.todo2.data.viewmodel.ToDoViewModel异常。

报错信息

java.lang.RuntimeException: Cannot create an instance of class com.ma.todo2.data.viewmodel.ToDoViewModel
    at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:322)
    at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:306)
    at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:280)
    at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.kt:128)
    at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:187)
    at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:153)
    at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:53)
    at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:35)
    at com.mahi.todo2.fragments.add.AddFragment.getMToDoViewModel(AddFragment.kt:31)
    at com.mahi.todo2.fragments.add.AddFragment.insertDataToDb(AddFragment.kt:78)
    at com.mahi.todo2.fragments.add.AddFragment.onOptionsItemSelected(AddFragment.kt:61)

关键代码行(AddFragment第31行)

private val mToDoViewModel: ToDoViewModel by viewModels()

相关代码

ToDoViewModel

class ToDoViewModel(application: Application): AndroidViewModel(application)
{
    private val toDoDao = ToDoDatabase.getDatabase(application).toDoDao()
    private val repository: ToDoRepository

    private val getAllData: LiveData<List<ToDoData>>

    init {
        repository = ToDoRepository(toDoDao)
        getAllData = repository.getAllData
    }

    fun insertData(toDoData: ToDoData){
        viewModelScope.launch(Dispatchers.IO) {
            repository.insertData(toDoData)
        }
    }
}

AddFragment

class AddFragment : Fragment() {

    private lateinit var title_et: EditText
    private lateinit var priorities_spinner: Spinner
    private lateinit var description_et : EditText

    private val mToDoViewModel: ToDoViewModel by viewModels()
    private val mSharedViewModel: SharedViewModel by viewModels()

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        // Inflate the layout for this fragment
      val view = inflater.inflate(R.layout.fragment_add, container, false)

      setHasOptionsMenu(true)

      title_et =  view.findViewById<EditText>(R.id.title_et)
      priorities_spinner  = view.findViewById<Spinner>(R.id.priorities_spinner)
      description_et = view.findViewById<EditText>(R.id.description_et)

      priorities_spinner.onItemSelectedListener = mSharedViewModel.listener

      return view

    }

    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        inflater.inflate(R.menu.add_fragment_menu, menu)
        super.onCreateOptionsMenu(menu, inflater)
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        if(item.itemId == R.id.menu_add){
            insertDataToDb()
        }
        return super.onOptionsItemSelected(item)
    }

    private fun insertDataToDb(){

        val mTitle = title_et.text.toString()
        val mPriority = priorities_spinner.selectedItem.toString()
        val mDescription = description_et.text.toString()

        val validation = mSharedViewModel.verifyDataFromUser(mTitle, mDescription)

        if(validation){
            //insert data to database
            val newData = ToDoData(0, mTitle, mSharedViewModel.parsePriority(mPriority), mDescription)

            mToDoViewModel.insertData(newData)
            Toast.makeText(requireContext(), "Successfully added!", Toast.LENGTH_SHORT).show()
            //Navigate back
            findNavController().navigate(R.id.action_addFragment_to_listFragment)
        }
        else{
            Toast.makeText(requireContext(), "Please fill out all fields.", Toast.LENGTH_SHORT).show() 
        }

    }
}

问题原因

ToDoViewModel继承自AndroidViewModel,这类ViewModel要求构造函数必须接收Application实例作为参数。但Fragment中默认的viewModels()委托使用的ViewModelFactory无法自动传递Application参数,导致ViewModelProvider无法实例化该类,从而抛出崩溃异常。

解决方法

修改Fragment中ViewModel的初始化代码,指定使用AndroidViewModelFactory并传入当前应用的Application实例,让Factory能正确创建需要Application参数的ViewModel:

private val mToDoViewModel: ToDoViewModel by viewModels {
    ViewModelProvider.AndroidViewModelFactory.getInstance(requireActivity().application)
}

替换原有的private val mToDoViewModel: ToDoViewModel by viewModels()即可解决问题。

内容的提问来源于stack exchange,提问作者Mahi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 05:25:30