2

I am making a note app with Room Database but the line noteViewModel = ViewModelProvider(this).get(NoteViewModel::class.java) in AddFragment.kt is making my app crash as soon as the AddFragment is opened. To view the full code find the github repository link in the end.

Below is the full code for AddFragment.kt

class AddFragment : Fragment() {
    private lateinit var binding: FragmentAddBinding
    private lateinit var noteViewModel: NoteViewModel

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        binding = DataBindingUtil.inflate(inflater, R.layout.fragment_add, container, false)


        //throwing error
        noteViewModel = ViewModelProvider(this).get(NoteViewModel::class.java)

        binding.addBtn.setOnClickListener {
            val noteTitle: String = binding.addTitleText.text.toString().trim()
            val noteBody: String = binding.addNoteText.text.toString().trim()

            when {
                noteTitle.isEmpty() -> {
                    Toast.makeText(this.activity, "Title missing.", Toast.LENGTH_SHORT).show()
                    binding.addTitleText.requestFocus()
                    return@setOnClickListener
                }
                noteBody.isEmpty() -> {
                    Toast.makeText(this.activity, "Note Body missing.", Toast.LENGTH_SHORT).show()
                    binding.addNoteText.requestFocus()
                    return@setOnClickListener
                }
                else -> {
                    noteViewModel.insertNote(Note(noteTitle, noteBody))
                    Toast.makeText(this.activity, "New Note Added.", Toast.LENGTH_SHORT).show()
                }
            }
        }

        return binding.root
    }

crash report

java.lang.RuntimeException: Cannot create an instance of class com.example.notezy.ViewModel.NoteViewModel
        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:275)
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:187)
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150)
        at com.example.notezy.Fragments.AddFragment.onCreateView(AddFragment.kt:33)
        at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2698)
        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:320)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1187)
        at androidx.fragment.app.FragmentManager.addAddedFragments(FragmentManager.java:2224)
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1997)
        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1953)
        at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1849)
        at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:413)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6669)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
     Caused by: java.lang.reflect.InvocationTargetException
        at java.lang.reflect.Constructor.newInstance0(Native Method)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:267)
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:187) 
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150) 
        at com.example.notezy.Fragments.AddFragment.onCreateView(AddFragment.kt:33) 
        at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2698) 
        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:320) 
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1187) 
        at androidx.fragment.app.FragmentManager.addAddedFragments(FragmentManager.java:2224) 
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1997) 
        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1953) 
        at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1849) 
        at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:413) 
        at android.os.Handler.handleCallback(Handler.java:873) 
        at android.os.Handler.dispatchMessage(Handler.java:99) 
        at android.os.Looper.loop(Looper.java:193) 
        at android.app.ActivityThread.main(ActivityThread.java:6669) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) 
     Caused by: java.lang.RuntimeException: cannot find implementation for com.example.notezy.Database.NoteDatabase. NoteDatabase_Impl does not exist
        at androidx.room.Room.getGeneratedImplementation(Room.java:94)
        at androidx.room.RoomDatabase$Builder.build(RoomDatabase.java:952)
        at com.example.notezy.Database.NoteDatabase$Companion.getDatabase(NoteDatabase.kt:24)
        at com.example.notezy.ViewModel.NoteViewModel.<init>(NoteViewModel.kt:18)
        at java.lang.reflect.Constructor.newInstance0(Native Method) 
        at java.lang.reflect.Constructor.newInstance(Constructor.java:343) 
        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:267) 
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:187) 
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150) 
        at com.example.notezy.Fragments.AddFragment.onCreateView(AddFragment.kt:33) 
        at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2698) 
        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:320) 
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1187) 
        at androidx.fragment.app.FragmentManager.addAddedFragments(FragmentManager.java:2224) 
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1997) 
        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1953) 
        at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1849) 
        at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:413) 
        at android.os.Handler.handleCallback(Handler.java:873) 
        at android.os.Handler.dispatchMessage(Handler.java:99) 
        at android.os.Looper.loop(Looper.java:193) 
        at android.app.ActivityThread.main(ActivityThread.java:6669) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) 

Github Link for the Repo: Click Here

Amir Dora.
  • 2,831
  • 4
  • 40
  • 61

3 Answers3

-1

The ViewModels (VMs) may theoretically be initialized as class level instance variables using the Kotlin extension library import androidx.fragment.app.viewModels method by viewmodels(). By initializing the VM as a class level instance var it can be accessed within the class.

class AddFragment : Fragment() {
    private lateinit var binding: FragmentAddBinding
    //private lateinit var noteViewModel: NoteViewModel
     private val noteViewModel: NoteViewModel by viewModels()

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        binding = DataBindingUtil.inflate(inflater, R.layout.fragment_add, container, false)


        //throwing error
        //noteViewModel = ViewModelProvider(this).get(NoteViewModel::class.java)

        binding.addBtn.setOnClickListener {
            val noteTitle: String = binding.addTitleText.text.toString().trim()
            val noteBody: String = binding.addNoteText.text.toString().trim()

            when {
                noteTitle.isEmpty() -> {
                    Toast.makeText(this.activity, "Title missing.", Toast.LENGTH_SHORT).show()
                    binding.addTitleText.requestFocus()
                    return@setOnClickListener
                }
                noteBody.isEmpty() -> {
                    Toast.makeText(this.activity, "Note Body missing.", Toast.LENGTH_SHORT).show()
                    binding.addNoteText.requestFocus()
                    return@setOnClickListener
                }
                else -> {
                    noteViewModel.insertNote(Note(noteTitle, noteBody))
                    Toast.makeText(this.activity, "New Note Added.", Toast.LENGTH_SHORT).show()
                }
            }
        }

        return binding.root
    }
Arda Kazancı
  • 8,341
  • 4
  • 28
  • 50
-1

Don't do anything besides inflating your view in onCreateView. Move the view setup and view model use into onViewCreated.

In fact, Fragment's constructor allows you to pass the layout ID directly, so you should never have to override onCreateView at all. You can switch your binding factory method from inflate to bind to attach to the already-inflated view.

class AddFragment : Fragment(R.layout.fragment_add) {
    private lateinit var binding: FragmentAddBinding
    private lateinit var noteViewModel: NoteViewModel

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        binding = DataBindingUtil.bind(view)

        noteViewModel = ViewModelProvider(this).get(NoteViewModel::class.java)

        binding.addBtn.setOnClickListener {
            // ...
        }

        return binding.root
    }
}
Tenfour04
  • 83,111
  • 11
  • 94
  • 154
-1

Your real error is Caused by: java.lang.RuntimeException: cannot find implementation for com.example.notezy.Database.NoteDatabase and to fix it you should :

  1. add id 'kotlin-kapt' to your plugins in build.gradle
  2. add implementation "androidx.room:room-ktx:$rootProject.roomVersion" dependency
  3. replace annotationProcessor to kapt annotation for your "androidx.room:room-compiler:$rootProject.roomVersion" dependecy

Happy Codding

i30mb1
  • 3,894
  • 3
  • 18
  • 34