Как реализовать выгрузку в recyclerview из roomdb

Пишу приложение. Во фрагменте есть ресайклер. В адаптер передаю массив с энтити. Пробовал забирать данные из базы через корутин, но они не отображаются. Пробовал инициализировать адаптер в onCreate, но вылезает ошибка, что лэйтинит не инициализирован. Не могу найти подходящий вариант

Lateinit выкидывает ошибку UinitializedPropertyAccesException

package com.example.conference.fragment

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 android.widget.Button
import android.widget.ImageButton
import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.conference.R
import com.example.conference.activity.AddContactActivity
import com.example.conference.activity.LoginActivity
import com.example.conference.adapter.ContactsRecyclerViewAdapter
import com.example.conference.db.ConferenceRoomDatabase
import com.google.firebase.auth.FirebaseAuth


class ProfileFragment : Fragment() {

    lateinit var adapter: ContactsRecyclerViewAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        adapter = ContactsRecyclerViewAdapter(ConferenceRoomDatabase.getDatabase(activity!!).contactDao().getAll())
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val v = inflater.inflate(R.layout.fragment_profile, container, false)
        v.findViewById<Button>(R.id.exitBtn).setOnClickListener {
            FirebaseAuth.getInstance().signOut()
            startActivity(Intent(activity, LoginActivity::class.java))
            activity?.finish()
        }

        val auth = FirebaseAuth.getInstance()

        v.findViewById<TextView>(R.id.emailTV).text = auth.currentUser?.email ?: "***@***.***"
        v.findViewById<ImageButton>(R.id.addContactIB).setOnClickListener {
            startActivity(Intent(activity, AddContactActivity::class.java))
        }

        val rv = v.findViewById<RecyclerView>(R.id.contactRV)
        rv.adapter = adapter
        rv.layoutManager = LinearLayoutManager(activity)

        return v
    }
}

Корутины. В ресайклере нет элементов если делать так.

package com.example.conference.fragment

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 android.widget.Button
import android.widget.ImageButton
import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.conference.R
import com.example.conference.activity.AddContactActivity
import com.example.conference.activity.LoginActivity
import com.example.conference.adapter.ContactsRecyclerViewAdapter
import com.example.conference.db.ConferenceRoomDatabase
import com.google.firebase.auth.FirebaseAuth
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch


class ProfileFragment : Fragment() {
    
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val v = inflater.inflate(R.layout.fragment_profile, container, false)
        v.findViewById<Button>(R.id.exitBtn).setOnClickListener {
            FirebaseAuth.getInstance().signOut()
            startActivity(Intent(activity, LoginActivity::class.java))
            activity?.finish()
        }

        val auth = FirebaseAuth.getInstance()

        v.findViewById<TextView>(R.id.emailTV).text = auth.currentUser?.email ?: "***@***.***"
        v.findViewById<ImageButton>(R.id.addContactIB).setOnClickListener {
            startActivity(Intent(activity, AddContactActivity::class.java))
        }

        GlobalScope.launch {
            val contacts = ConferenceRoomDatabase.getDatabase(activity!!).contactDao().getAll()
            val rv = v.findViewById<RecyclerView>(R.id.contactRV)
            rv.adapter = ContactsRecyclerViewAdapter(contacts)
            rv.layoutManager = LinearLayoutManager(activity)
        }

        return v
    }
}

Адаптер

package com.example.conference.adapter

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.conference.R
import com.example.conference.db.entity.ContactEntity
import kotlinx.android.synthetic.main.contact_item_view.view.*

class ContactsRecyclerViewAdapter(private val contacts: List<ContactEntity>): RecyclerView.Adapter<ContactsRecyclerViewAdapter.ContactViewHolder>() {


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

    override fun onBindViewHolder(holder: ContactViewHolder, position: Int) {
        holder.bind(contacts[position])
    }

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

    inner class ContactViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        var name: TextView = itemView.contactNameTV
        var surname: TextView = itemView.contactSurnameTV
        var email: TextView = itemView.contactEmailTV
        fun bind(contact: ContactEntity) {
            name.text = contact.name
            surname.text = contact.surname
            email.text = contact.email
        }
    }
}

Как элементы поступают в бд

package com.example.conference.activity

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import com.example.conference.R
import com.example.conference.db.ConferenceRoomDatabase
import com.example.conference.db.entity.ContactEntity
import kotlinx.android.synthetic.main.activity_add_contact.*
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch

class AddContactActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_add_contact)

        backIB.setOnClickListener {
            finish()
        }

        addContactBtn.setOnClickListener {
            GlobalScope.launch {
                val email = contactEmailET.text.toString()
                val db = ConferenceRoomDatabase.getDatabase(this@AddContactActivity)
                val contact = ContactEntity()
                contact.email = email
                contact.name = "Имя"
                contact.surname = "Фамилия"
                db.contactDao().insert(contact)
                db.close()
                //TODO селать проверку
            }
        }
    }
}

Ответы (2 шт):

Автор решения: Денис Виданов

Вам нужно локализовать проблему для начала. Тут либо с запросом что-то не так. Второй вариант это то что вы назначили адаптер до layout manager. Выходит что когда пришли данные и назначился адаптер, у recyclerView нет layoutManager и он не знает как отрисовать layout. Попробуйте сначала назначить layout manager. И ещё создавать адаптер каждый раз когда приходят данные накладно. Нужно обновлять список внутри адаптера и вызывать notifyDatasetChanged

→ Ссылка
Автор решения: Алексей Козедубов

Отгадка была проста. Во всем виновата эта строчка

suspend fun insert(ce: ContactEntity)

У меня было так

suspend fun insert(ce: ContactEntity) {}
→ Ссылка