ViewModel使用Database Room错误Android Studio

问题描述 投票:0回答:1

我目前面临一个错误,其中 homefragment 并使用 viewmodel、recyclerview 来实现 CRUD。错误是我在loginfragment中使用id和密码登录的地方,它出现错误,并且错误说无法创建类NoteViewModel的实例,而且我不知道哪里出了问题

这是主页片段

package com.example.challenge4binar

import android.app.AlertDialog
import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.navigation.findNavController
import com.example.challenge4binar.databinding.FragmentHomeBinding

// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"

/**
 * A simple [Fragment] subclass.
 * Use the [HomeFragment.newInstance] factory method to
 * create an instance of this fragment.
 */
class HomeFragment : Fragment() {
    // TODO: Rename and change types of parameters
    private var param1: String? = null
    private var param2: String? = null
    private var _binding: FragmentHomeBinding? = null
    private val binding get() = _binding!!
    private lateinit var sharedPreferences: SharedPreferences

    private val noteViewModel: NoteViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        arguments?.let {
            param1 = it.getString(ARG_PARAM1)
            param2 = it.getString(ARG_PARAM2)
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        _binding = FragmentHomeBinding.inflate(inflater, container, false)
        sharedPreferences = requireContext().getSharedPreferences("myPrefs", Context.MODE_PRIVATE)
        return binding.root
    }

    companion object {
        /**
         * Use this factory method to create a new instance of
         * this fragment using the provided parameters.
         *
         * @param param1 Parameter 1.
         * @param param2 Parameter 2.
         * @return A new instance of fragment HomeFragment.
         */
        // TODO: Rename and change types and number of parameters
        @JvmStatic
        fun newInstance(param1: String, param2: String) =
            HomeFragment().apply {
                arguments = Bundle().apply {
                    putString(ARG_PARAM1, param1)
                    putString(ARG_PARAM2, param2)
                }
            }
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.tvLogout.setOnClickListener {
            it.findNavController().navigate(R.id.action_homeFragment_to_loginFragment)
        }
        val adapter = NoteAdapter(requireContext(), noteViewModel, mutableListOf())

        val recyclerView = binding.rvNote
        recyclerView.adapter = adapter

        noteViewModel.allNotes.observe(viewLifecycleOwner) { notes ->
            if (notes.isEmpty()) {
                binding.tvDatakosong.visibility = View.VISIBLE
                binding.rvNote.visibility = View.GONE
            } else {
                binding.tvDatakosong.visibility = View.GONE
                binding.rvNote.visibility = View.VISIBLE
                adapter.setNotes(notes)
            }
        }

        binding.btnTambahHome.setOnClickListener{
            dialogtambah()
        }
    }

    fun dialogtambah() {
        val builder = AlertDialog.Builder(requireContext())
        val inflater = layoutInflater
        val dialogView = inflater.inflate(R.layout.tambah, null)

        builder.setView(dialogView)
        builder.setTitle("Tambah Data")

        builder.setPositiveButton("Add") { dialog, _ ->
            val contentEditText = dialogView.findViewById<EditText>(R.id.et_judul_tambah)
            val titleEditText = dialogView.findViewById<EditText>(R.id.et_catatan_tambah)
            val notecontent = contentEditText.text.toString()
            val titlenote = titleEditText.text.toString()

            if (notecontent.isNotEmpty() && titlenote.isNotEmpty()) {
                val newNote = Note(note = notecontent, title = titlenote)
                noteViewModel.insert(newNote)
            }
        }
    }
}

这是noteviewmodel

package com.example.challenge4binar

import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch

class NoteViewModel(private val repository: NoteRepository):ViewModel() {

    val allNotes: LiveData<List<Note>> =repository.allNotes

    fun insert(note: Note) = viewModelScope.launch {
        repository.insert(note)
    }

    fun update(note:Note) = viewModelScope.launch {
        repository.update(note)
    }

    fun delete(note:Note) = viewModelScope.launch {
        repository.delete(note)
    }
}

这是 noteRepository

package com.example.challenge4binar

import androidx.lifecycle.LiveData

class NoteRepository(private val noteDao: NoteDao) {

    val allNotes: LiveData<List<Note>> = noteDao.getAllNotes()

    suspend fun insert(note: Note){
        noteDao.insert(note)
    }

    suspend fun update(note:Note){
        noteDao.update(note)
    }

    suspend fun delete (note:Note){
        noteDao.delete(note)
    }
}

这是注释

@Entity(tableName = "notes")
data class Note(
    @PrimaryKey(autoGenerate = true)val id:Long = 0,
    var title:String,
    var note:String
)

这是笔记本适配器

package com.example.challenge4binar

import android.app.AlertDialog
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.EditText
import android.widget.ImageView
import androidx.recyclerview.widget.RecyclerView

class NoteAdapter(
    private val context: Context,
    private val noteViewModel: NoteViewModel,
    private val notes: MutableList<Note>):RecyclerView.Adapter<NoteAdapter.ViewHolder>() {


    inner class ViewHolder(itemView: View):RecyclerView.ViewHolder(itemView) {
        val deleteButton : ImageView = itemView.findViewById(R.id.btn_delete_rv)
        val updateButton :ImageView = itemView.findViewById(R.id.btn_update_rv)

        fun bind(note: Note){
            deleteButton.setOnClickListener{
                dialoghapus(note)

            }
            updateButton.setOnClickListener {
                dialogupdate(note)
            }
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoteAdapter.ViewHolder {
        val itemView = LayoutInflater.from(parent.context).inflate(R.layout.delete, parent, false)
        return ViewHolder(itemView)
    }

    override fun onBindViewHolder(holder: NoteAdapter.ViewHolder, position: Int) {
        val note = notes[position]
        holder.bind(note)
    }

    override fun getItemCount(): Int {
        return notes.size
    }

    private fun dialoghapus(note: Note) {
        val builder = AlertDialog.Builder(context)
        builder.setTitle("Delete Note")

        builder.setPositiveButton("Delete") { dialog, _ ->
            noteViewModel.delete(note)

            val position = notes.indexOf(note)
            if (position != -1) {
                notes.removeAt(position)
                notifyItemRemoved(position)
            }
            dialog.dismiss()
        }

        builder.setNegativeButton("Cancel") { dialog, _ ->
            dialog.dismiss()
        }
        builder.show()
    }

    private fun dialogupdate(note: Note) {
        val builder = AlertDialog.Builder(context)
        val inflater = LayoutInflater.from(context)
        val dialogView = inflater.inflate(R.layout.update, null)

        // Use var instead of val for these variables
        var etJudul = dialogView.findViewById<EditText>(R.id.et_judul_edit)
        var etCatatan = dialogView.findViewById<EditText>(R.id.et_catatan_edit)
        val btnInput = dialogView.findViewById<Button>(R.id.btn_edit)

        etJudul.setText(note.title)
        etCatatan.setText(note.note)

        builder.setView(dialogView)
        builder.setTitle("Update Note")

        val dialog = builder.create()

        btnInput.setOnClickListener {
            // Handle the update logic here
            val updatedTitle = etJudul.text.toString()
            val updatedNote = etCatatan.text.toString()

            if (updatedTitle.isNotEmpty() && updatedNote.isNotEmpty()) {
                // Update the note with the new data
                note.title = updatedTitle
                note.note = updatedNote

                // Call your update method or ViewModel function here
                // For example: noteViewModel.update(note)

                // Dismiss the dialog when the update is done
                dialog.dismiss()
            } else {
                // Display an error message or handle empty fields
            }
        }

        dialog.show()
    }
    fun setNotes(newNotes: List<Note>){
        notes.clear()
        notes.addAll(newNotes)
    }


}
android kotlin android-room viewmodel android-livedata
1个回答
0
投票

这是因为您将 NoteRepository 传递给 NoteViewModel 构造函数,并使用委托函数在片段中实例化 viewModel,因此它不会获得任何对其的引用。

那么你将需要一个 ViewModelFactory, https://developer.android.com/topic/libraries/architecture/viewmodel/viewmodel-factories

© www.soinside.com 2019 - 2024. All rights reserved.