Search code examples
androidkotlinkotlin-coroutinesandroid-viewmodelandroid-mvvm

instance of Dao class is not being initialized correctly


I want to load data from database into the RecyclerView using Kotlin Coroutine, but it does not load data at first launch, but when App is restarted it loads up data correctly. It seems there is something wrong in repository class:

NoteDao.kt is:

@Dao
interface NoteDAO {

    @Query("SELECT * FROM NoteTable ORDER BY noteDate DESC")
    fun findAllNotes(): List<Note>

}

NoteRepository.kt

class NoteRepository(application: Application) {

    private var allNotes = MutableLiveData<List<Note>>()

    private val noteDAO = NoteDatabase.getDatabase(application).getNoteDao() // Issue is caused by this line because data is not assigned to noteDAO 

    fun getAllNotes(): MutableLiveData<List<Note>> {
        CoroutineScope(Dispatchers.IO).launch {
            val noteData = noteDAO.findAllNotes()
            allNotes.postValue(NoteData)
        }
        return allNotes   // it also returns empty List with size = 0
    }

}

adapter class is

class NoteAdapter(val context: Context): RecyclerView.Adapter<NoteAdapter.NoteHolder>() {

    private var allNotes: List<Note> = ArrayList()

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

    override fun onBindViewHolder(holder: NoteHolder, position: Int) {
        val currentNote = allNotes[position]
        holder.title.text = currentNote.title
        holder.date.text = DateUtils.getDate(Date(currentNote.date))

    }

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

    fun addNotes(allNotes: List<Note>) {
        this.allNotes = allNotes
        notifyDataSetChanged()
    }

    inner class NoteHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        var title: LabelTextView = itemView.findViewById(R.id.item_title)
        var date: LabelTextView = itemView.findViewById(R.id.item_date)
    }

}

and ViewModel is

class NoteViewModel(
    application: Application
): AndroidViewModel(application) {

    private var repository = NoteRepository(application)

    private var _allNotes = repository.getAllNotes()

    val allNotes: LiveData<List<Note>>
        get() = _allNotes
}

and lastly it is attached in MainActivity

class MainActivity : AppCompatActivity(){

    private lateinit var mNoteViewModel: NoteViewModel
    private lateinit var mNoteAdapter: NoteAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setSupportActionBar(toolbar)    

        mNoteAdapter = NoteAdapter(this)

        mNoteViewModel = ViewModelProviders.of(this).get(NoteViewModel::class.java)
        mNoteViewModel.allNotes.observe(
            this, Observer {
                Log.e("MAIN_ACTIVITY", "Called...") // it is printed in Log but data is not recieved from repository
                mNoteAdapter.addNotes(it)
            }
        )

        rv_log.layoutManager = GridLayoutManager(this, 2, GridLayoutManager.VERTICAL, false)

        mNoteAdapter.notifyDataSetChanged()
        rv_log.adapter = mNoteAdapter
    }

}

that all is not loading and displaying data in RecyclerView.


Solution

  • It seems that the issue is with getAllNotes() means CoroutineScope is not working correctly. You should use Flow API and change Dao methods to

    @Query("SELECT * FROM NoteTable ORDER BY noteDate DESC")
    fun findAllNotes(): Flow<List<Note>>
    

    after this you must change NoteRepository class and put init block as:

    init {
        CoroutineScope(Dispatchers.IO).launch {
             val noteData = noteDAO.findAllNotes()
             noteData.collect{ // it is related to Flow API
                 allNotes.postValue(it)
             }
        }
    } 
    

    and just return allNotes in getAllNotes()

    fun getAllNotes(): MutableLiveData<List<Note>> {            
        return allNotes 
    }
    

    now you must check if it works?