kotlinandroid-fragmentsmvvmandroid-recyclerviewroom

lateinit property remindersViewModel has not been initialized


I am displaying two fragments in the activity with recyclerViews. I am trying to add a new item to the recycler view but I am getting : "lateinit property remindersViewModel has not been initialized" error. I am already trying to initialise it in the fragments.

My Fragment 1:


import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.bubblereminder.room.Reminders
import com.example.bubblereminder.room.RemindersListAdapter
import com.example.bubblereminder.room.RemindersViewModel

class ScheduledFragment : Fragment() {
    private lateinit var reminderViewModel: RemindersViewModel

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        val v = inflater.inflate(R.layout.fragment_scheduled, container, false)

        return v
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)

        val recyclerView = view?.findViewById<RecyclerView>(R.id.recycler_scheduled)
        val adapter = context?.let { RemindersListAdapter(it) }
        if (recyclerView != null) {
            recyclerView.adapter = adapter
        }
        if (recyclerView != null) {
            recyclerView.layoutManager = LinearLayoutManager(context)
        }

        this.reminderViewModel = ViewModelProvider(this).get(RemindersViewModel::class.java)
        reminderViewModel.allReminders.observe(viewLifecycleOwner, Observer { reminders ->
            // Update the cached copy of the words in the adapter.
            reminders?.let {
                if (adapter != null) {
                    adapter.setReminders(it)
                }
            }
        })
    }
}

My Fragment 2:

    package com.example.bubblereminder

import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.bubblereminder.room.Reminders
import com.example.bubblereminder.room.RemindersListAdapter
import com.example.bubblereminder.room.RemindersViewModel

class DoneFragment : Fragment() {
    private lateinit var reminderViewModel: RemindersViewModel

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        val v = inflater.inflate(R.layout.fragment_scheduled, container, false)

        return v
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)

        val recyclerView = view?.findViewById<RecyclerView>(R.id.recycler_scheduled)
        val adapter = context?.let { RemindersListAdapter(it) }
        if (recyclerView != null) {
            recyclerView.adapter = adapter
        }
        if (recyclerView != null) {
            recyclerView.layoutManager = LinearLayoutManager(context)
        }

        this.reminderViewModel = ViewModelProvider(this).get(RemindersViewModel::class.java)
        reminderViewModel.allReminders.observe(viewLifecycleOwner, Observer { reminders ->
            // Update the cached copy of the words in the adapter.
            reminders?.let {
                if (adapter != null) {
                    adapter.setReminders(it)
                }
            }
        })
    }
}

My Activity:

    package com.example.bubblereminder

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.FrameLayout
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.bubblereminder.room.Reminders
import com.example.bubblereminder.room.RemindersDao
import com.example.bubblereminder.room.RemindersListAdapter
import com.example.bubblereminder.room.RemindersViewModel
import com.ramotion.circlemenu.CircleMenuView

class MainActivity : AppCompatActivity() {
    private lateinit var remindersViewModel: RemindersViewModel
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setupMenuEventListener()
        setupFragments(R.id.fragment_container1, ScheduledFragment())
        setupFragments(R.id.fragment_container2, DoneFragment())
    }

    private fun setupMenuEventListener() {
        val circleMenu = findViewById<CircleMenuView>(R.id.circle_menu)
        circleMenu.eventListener = object : CircleMenuView.EventListener() {

            override fun onButtonClickAnimationEnd(view: CircleMenuView, index: Int) {
                when (index) {
                    0 -> {
                        remindersViewModel.insert(Reminders(0,"Sample Reminder Text"))
                        val confirmToast = "Task 1 Finished"
                        Toast.makeText(this@MainActivity, confirmToast, Toast.LENGTH_SHORT)
                            .show()
                    }
                    1 -> {
                        val confirmToast = "Task 2 Finished"
                        Toast.makeText(this@MainActivity, confirmToast, Toast.LENGTH_SHORT)
                            .show()
                    }
                    2 -> {
                        val confirmToast = "Task 3 Finished"
                        Toast.makeText(this@MainActivity, confirmToast, Toast.LENGTH_SHORT)
                            .show()
                    }
                    3 -> {
                        val confirmToast = "Task 4 Finished"
                        Toast.makeText(this@MainActivity, confirmToast, Toast.LENGTH_SHORT)
                            .show()
                    }
                    4 -> {
                        val confirmToast = "Task 5 Finished"
                        Toast.makeText(this@MainActivity, confirmToast, Toast.LENGTH_SHORT)
                            .show()
                    }
                }
            }
        }
    }
    private fun setupFragments(id:Int , frag:Fragment){
        var fragmentManager = supportFragmentManager
        fragmentManager.beginTransaction()
            .replace(id, frag)
            .commit()
    }
}

I tried to initialise the view model in the activity but I was not able to.


Solution

  • Each remindersViewModel variable you have is completely separate, and by marking them as lateinit you're promising to set a value on them before you try to read them. You're doing that in the fragments, but you're not initialising the one in MainActivity before you call insert on it