创建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
相关产品推荐
相关产品推荐

