我正在创建一个简单的待办事项应用程序。当尝试创建视图模型时。我遇到异常并且应用程序崩溃了。
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)
第 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)
}
}
}
添加片段
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){
//iinsert 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()
}
}
}
1。创建一个ViewModelFactory:
class ToDoViewModelFactory(private val application: Application) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(ToDoViewModel::class.java)) {
@Suppress("UNCHECKED_CAST")
return ToDoViewModel(application) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
更新您的 AddFragment 以使用 ViewModelFactory:
类 AddFragment : Fragment() { // 其他成员变量...
// Create a ViewModelFactory instance using the Application context
private val viewModelFactory: ToDoViewModelFactory by lazy {
ToDoViewModelFactory(requireActivity().application)
}
// Use ViewModelProvider with the factory to create ViewModel instances
private val mToDoViewModel: ToDoViewModel by viewModels { viewModelFactory }
private val mSharedViewModel: SharedViewModel by viewModels()
// Fragment code...
private fun insertDataToDb() {
// Your insertDataToDb function...
}
// methods...
}
此方法允许您使用自定义 ViewModelFactory 创建 ToDoViewModel 的实例。需要注意的是,ToDoViewModelFactory 需要访问应用程序上下文,这就是我们将其作为参数传递的原因。
通过这些更改,ViewModelFactory 将用于创建 ToDoViewModel 的实例,您可以确保在 ViewModel 创建过程中正确提供任何必要的依赖项。
由于您没有使用任何依赖注入,因此您必须使视图模型工厂在视图模型中传递参数