kotlin ViewModel using Database Room error Android Studio

kcwpcxri  于 5个月前  发布在  Kotlin
关注(0)|答案(2)|浏览(87)

我目前正面临一个错误,在那里的家庭片段和使用viewmodel,recyclerview实现CRUD.错误是,我在登录时使用id和密码在loginfragment,它出现错误,错误说,不能创建类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)
            }
        }
    }
}

字符串
这不是视图模型

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)
    }
}


这是notRepository

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)
    }
}


这是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)
    }

}

y0u0uwnf

y0u0uwnf1#

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

NoteRepository

class NoteRepository {
    fun checkWorking() {
        Log.d("NoteViewModel_Check", "checkWorking: ")
    }
}

字符串

NoteViewModel

class NoteViewModel(private val repository: NoteRepository) : ViewModel() {
    fun checkWorking() {
        repository.checkWorking()
    }

}

NoteViewModelFactory

class NoteViewModelFactory(private val noteRepository: NoteRepository) : ViewModelProvider.Factory {

    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(NoteViewModel::class.java)) {
            return NoteViewModel(noteRepository) as T
        }
        throw IllegalArgumentException("Unknown ViewModel")
    }

}


用法:MainActivity

class MainActivity : AppCompatActivity() {

    private val noteViewModel by viewModels<NoteViewModel> { NoteViewModelFactory(NoteRepository()) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        noteViewModel.checkWorking()
}
}


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

更新二:

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

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

cnwbcb6i

cnwbcb6i2#

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

相关问题