kotlin ViewModel using Database Room error Android Studio

kcwpcxri  于 2023-11-21  发布在  Kotlin
关注(0)|答案(2)|浏览(318)

我目前正面临一个错误,在那里的家庭片段和使用viewmodel,recyclerview实现CRUD.错误是,我在登录时使用id和密码在loginfragment,它出现错误,错误说,不能创建类NoteViewModel的示例,我不知道哪里的部分是错误的
这是家庭片段

  1. package com.example.challenge4binar
  2. import android.app.AlertDialog
  3. import android.content.Context
  4. import android.content.SharedPreferences
  5. import android.os.Bundle
  6. import android.view.LayoutInflater
  7. import android.view.View
  8. import android.view.ViewGroup
  9. import android.widget.EditText
  10. import androidx.fragment.app.Fragment
  11. import androidx.fragment.app.viewModels
  12. import androidx.navigation.findNavController
  13. import com.example.challenge4binar.databinding.FragmentHomeBinding
  14. // TODO: Rename parameter arguments, choose names that match
  15. // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
  16. private const val ARG_PARAM1 = "param1"
  17. private const val ARG_PARAM2 = "param2"
  18. /**
  19. * A simple [Fragment] subclass.
  20. * Use the [HomeFragment.newInstance] factory method to
  21. * create an instance of this fragment.
  22. */
  23. class HomeFragment : Fragment() {
  24. // TODO: Rename and change types of parameters
  25. private var param1: String? = null
  26. private var param2: String? = null
  27. private var _binding: FragmentHomeBinding? = null
  28. private val binding get() = _binding!!
  29. private lateinit var sharedPreferences: SharedPreferences
  30. private val noteViewModel: NoteViewModel by viewModels()
  31. override fun onCreate(savedInstanceState: Bundle?) {
  32. super.onCreate(savedInstanceState)
  33. arguments?.let {
  34. param1 = it.getString(ARG_PARAM1)
  35. param2 = it.getString(ARG_PARAM2)
  36. }
  37. }
  38. override fun onCreateView(
  39. inflater: LayoutInflater, container: ViewGroup?,
  40. savedInstanceState: Bundle?
  41. ): View? {
  42. // Inflate the layout for this fragment
  43. _binding = FragmentHomeBinding.inflate(inflater, container, false)
  44. sharedPreferences = requireContext().getSharedPreferences("myPrefs", Context.MODE_PRIVATE)
  45. return binding.root
  46. }
  47. companion object {
  48. /**
  49. * Use this factory method to create a new instance of
  50. * this fragment using the provided parameters.
  51. *
  52. * @param param1 Parameter 1.
  53. * @param param2 Parameter 2.
  54. * @return A new instance of fragment HomeFragment.
  55. */
  56. // TODO: Rename and change types and number of parameters
  57. @JvmStatic
  58. fun newInstance(param1: String, param2: String) =
  59. HomeFragment().apply {
  60. arguments = Bundle().apply {
  61. putString(ARG_PARAM1, param1)
  62. putString(ARG_PARAM2, param2)
  63. }
  64. }
  65. }
  66. override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
  67. super.onViewCreated(view, savedInstanceState)
  68. binding.tvLogout.setOnClickListener {
  69. it.findNavController().navigate(R.id.action_homeFragment_to_loginFragment)
  70. }
  71. val adapter = NoteAdapter(requireContext(), noteViewModel, mutableListOf())
  72. val recyclerView = binding.rvNote
  73. recyclerView.adapter = adapter
  74. noteViewModel.allNotes.observe(viewLifecycleOwner) { notes ->
  75. if (notes.isEmpty()) {
  76. binding.tvDatakosong.visibility = View.VISIBLE
  77. binding.rvNote.visibility = View.GONE
  78. } else {
  79. binding.tvDatakosong.visibility = View.GONE
  80. binding.rvNote.visibility = View.VISIBLE
  81. adapter.setNotes(notes)
  82. }
  83. }
  84. binding.btnTambahHome.setOnClickListener{
  85. dialogtambah()
  86. }
  87. }
  88. fun dialogtambah() {
  89. val builder = AlertDialog.Builder(requireContext())
  90. val inflater = layoutInflater
  91. val dialogView = inflater.inflate(R.layout.tambah, null)
  92. builder.setView(dialogView)
  93. builder.setTitle("Tambah Data")
  94. builder.setPositiveButton("Add") { dialog, _ ->
  95. val contentEditText = dialogView.findViewById<EditText>(R.id.et_judul_tambah)
  96. val titleEditText = dialogView.findViewById<EditText>(R.id.et_catatan_tambah)
  97. val notecontent = contentEditText.text.toString()
  98. val titlenote = titleEditText.text.toString()
  99. if (notecontent.isNotEmpty() && titlenote.isNotEmpty()) {
  100. val newNote = Note(note = notecontent, title = titlenote)
  101. noteViewModel.insert(newNote)
  102. }
  103. }
  104. }
  105. }

字符串
这不是视图模型

  1. package com.example.challenge4binar
  2. import androidx.lifecycle.LiveData
  3. import androidx.lifecycle.ViewModel
  4. import androidx.lifecycle.viewModelScope
  5. import kotlinx.coroutines.launch
  6. class NoteViewModel(private val repository: NoteRepository):ViewModel() {
  7. val allNotes: LiveData<List<Note>> =repository.allNotes
  8. fun insert(note: Note) = viewModelScope.launch {
  9. repository.insert(note)
  10. }
  11. fun update(note:Note) = viewModelScope.launch {
  12. repository.update(note)
  13. }
  14. fun delete(note:Note) = viewModelScope.launch {
  15. repository.delete(note)
  16. }
  17. }


这是notRepository

  1. package com.example.challenge4binar
  2. import androidx.lifecycle.LiveData
  3. class NoteRepository(private val noteDao: NoteDao) {
  4. val allNotes: LiveData<List<Note>> = noteDao.getAllNotes()
  5. suspend fun insert(note: Note){
  6. noteDao.insert(note)
  7. }
  8. suspend fun update(note:Note){
  9. noteDao.update(note)
  10. }
  11. suspend fun delete (note:Note){
  12. noteDao.delete(note)
  13. }
  14. }


这是Note

  1. @Entity(tableName = "notes")
  2. data class Note(
  3. @PrimaryKey(autoGenerate = true)val id:Long = 0,
  4. var title:String,
  5. var note:String
  6. )


这不是一个适配器

  1. package com.example.challenge4binar
  2. import android.app.AlertDialog
  3. import android.content.Context
  4. import android.view.LayoutInflater
  5. import android.view.View
  6. import android.view.ViewGroup
  7. import android.widget.Button
  8. import android.widget.EditText
  9. import android.widget.ImageView
  10. import androidx.recyclerview.widget.RecyclerView
  11. class NoteAdapter(
  12. private val context: Context,
  13. private val noteViewModel: NoteViewModel,
  14. private val notes: MutableList<Note>):RecyclerView.Adapter<NoteAdapter.ViewHolder>() {
  15. inner class ViewHolder(itemView: View):RecyclerView.ViewHolder(itemView) {
  16. val deleteButton : ImageView = itemView.findViewById(R.id.btn_delete_rv)
  17. val updateButton :ImageView = itemView.findViewById(R.id.btn_update_rv)
  18. fun bind(note: Note){
  19. deleteButton.setOnClickListener{
  20. dialoghapus(note)
  21. }
  22. updateButton.setOnClickListener {
  23. dialogupdate(note)
  24. }
  25. }
  26. }
  27. override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoteAdapter.ViewHolder {
  28. val itemView = LayoutInflater.from(parent.context).inflate(R.layout.delete, parent, false)
  29. return ViewHolder(itemView)
  30. }
  31. override fun onBindViewHolder(holder: NoteAdapter.ViewHolder, position: Int) {
  32. val note = notes[position]
  33. holder.bind(note)
  34. }
  35. override fun getItemCount(): Int {
  36. return notes.size
  37. }
  38. private fun dialoghapus(note: Note) {
  39. val builder = AlertDialog.Builder(context)
  40. builder.setTitle("Delete Note")
  41. builder.setPositiveButton("Delete") { dialog, _ ->
  42. noteViewModel.delete(note)
  43. val position = notes.indexOf(note)
  44. if (position != -1) {
  45. notes.removeAt(position)
  46. notifyItemRemoved(position)
  47. }
  48. dialog.dismiss()
  49. }
  50. builder.setNegativeButton("Cancel") { dialog, _ ->
  51. dialog.dismiss()
  52. }
  53. builder.show()
  54. }
  55. private fun dialogupdate(note: Note) {
  56. val builder = AlertDialog.Builder(context)
  57. val inflater = LayoutInflater.from(context)
  58. val dialogView = inflater.inflate(R.layout.update, null)
  59. // Use var instead of val for these variables
  60. var etJudul = dialogView.findViewById<EditText>(R.id.et_judul_edit)
  61. var etCatatan = dialogView.findViewById<EditText>(R.id.et_catatan_edit)
  62. val btnInput = dialogView.findViewById<Button>(R.id.btn_edit)
  63. etJudul.setText(note.title)
  64. etCatatan.setText(note.note)
  65. builder.setView(dialogView)
  66. builder.setTitle("Update Note")
  67. val dialog = builder.create()
  68. btnInput.setOnClickListener {
  69. // Handle the update logic here
  70. val updatedTitle = etJudul.text.toString()
  71. val updatedNote = etCatatan.text.toString()
  72. if (updatedTitle.isNotEmpty() && updatedNote.isNotEmpty()) {
  73. // Update the note with the new data
  74. note.title = updatedTitle
  75. note.note = updatedNote
  76. // Call your update method or ViewModel function here
  77. // For example: noteViewModel.update(note)
  78. // Dismiss the dialog when the update is done
  79. dialog.dismiss()
  80. } else {
  81. // Display an error message or handle empty fields
  82. }
  83. }
  84. dialog.show()
  85. }
  86. fun setNotes(newNotes: List<Note>){
  87. notes.clear()
  88. notes.addAll(newNotes)
  89. }
  90. }

y0u0uwnf

y0u0uwnf1#

这是因为您将NoteRepository传递给NoteViewModel构造函数,并使用delegate函数示例化片段中的viewModel,因此它不会获得对它的任何引用。
您将需要一个ViewModelFactory,https://developer.android.com/topic/libraries/architecture/viewmodel/viewmodel-factories
更新日期:

NoteRepository

  1. class NoteRepository {
  2. fun checkWorking() {
  3. Log.d("NoteViewModel_Check", "checkWorking: ")
  4. }
  5. }

字符串

NoteViewModel

  1. class NoteViewModel(private val repository: NoteRepository) : ViewModel() {
  2. fun checkWorking() {
  3. repository.checkWorking()
  4. }
  5. }

NoteViewModelFactory

  1. class NoteViewModelFactory(private val noteRepository: NoteRepository) : ViewModelProvider.Factory {
  2. override fun <T : ViewModel> create(modelClass: Class<T>): T {
  3. if (modelClass.isAssignableFrom(NoteViewModel::class.java)) {
  4. return NoteViewModel(noteRepository) as T
  5. }
  6. throw IllegalArgumentException("Unknown ViewModel")
  7. }
  8. }


用法:MainActivity

  1. class MainActivity : AppCompatActivity() {
  2. private val noteViewModel by viewModels<NoteViewModel> { NoteViewModelFactory(NoteRepository()) }
  3. override fun onCreate(savedInstanceState: Bundle?) {
  4. super.onCreate(savedInstanceState)
  5. setContentView(R.layout.activity_main)
  6. noteViewModel.checkWorking()
  7. }
  8. }


让我知道,如果你仍然面临的问题。

更新二:

只需在您的HomeFragment中替换此内容,您将在LogCat中找到日志

  1. val database by lazy { AppDatabase.getDatabase(requireContext()) }
  2. val noteDao by lazy { database!!.noteDao() }

展开查看全部
cnwbcb6i

cnwbcb6i2#

你不能直接将数据传递给viewModel,你必须创建一个viewModelFactory,它将接收数据并为你创建一个ViewModel对象。然后你可以在你的片段或Activity中使用这个viewModel对象。在互联网上有很多关于viewmodel和viewmodel工厂的资源。

相关问题