'ListView do not display data from Room database (see Update #2)

In this Android project I am developing, I have 1 activity with 2 fragments: one has a ListView and the other a formulary to insert the data being displayed on the ListView. The data is being stored on a Room database. The insertion part was working fine, but after some change in the code (do not remeber what change), right now is not working. Even when the insertion was working, the data was not being displayed on the ListView (that I suspect is due something wrong about the adapter implementation, despite the correct data being returned from the queries in the adapter). Anyone can spot what's wrong with my code?

Update #1

Adding allowMainThreadQueries() to the . databaseBuild call (to remove the database code from the coroutine) make the insertion work (and some methods from the Adapter are being executed), but no data are being displayed on the ListView

Update #2

I finally get to make work the ListView (code below it is final version for the adapter). Now I just need a way to make database persistence without use the allowMainThreadQueries().

DataAdapter

class DataAdapter(val context: Context?): BaseAdapter() {
    lateinit var mInflater: LayoutInflater

    init {
        mInflater = LayoutInflater.from(context)
    }

    override fun getCount(): Int {
        var count = 0
        if(context != null) {
            val db = Room.databaseBuilder(context, ListDatabase::class.java, "data").allowMainThreadQueries().build()
            count = db.userDao().getAll().size
        }
        return count
    }

    override fun getItem(p: Int): Any {
        var user = Usuario(0)
        if(context != null) {
            val db = Room.databaseBuilder(context, ListDatabase::class.java, "data").allowMainThreadQueries().build()
            user = db.userDao().getAll()[p]
        }
        return user
    }

    override fun getItemId(p: Int): Long {
        return p.toLong()
    }

    override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
        if(convertView == null) {
            val view = mInflater.inflate(R.layout.list_item, null)
            val textView = view.findViewById(R.id.text) ?: TextView(context)

            val user = getItem(position) as Usuario
            val text = "${user.firstName} ${user.lastName}"
            textView.text = text

            return textView
        } else {
            val textView = convertView.findViewById(R.id.text) ?: TextView(context)

            val user = getItem(position) as Usuario
            val firstName = user.firstName
            val lastName = user.lastName
            val text = "$firstName $lastName"
            textView.text = text

            return textView
        }
    }
}

FirstFragment.kt

class FirstFragment : Fragment() {
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        val binding = FragmentFirstBinding.inflate(inflater, container, false)

        binding.list.adapter = DataAdapter(this.context)
        binding.list.setOnItemClickListener { _, _, position, _ ->
            val context = this.context
            GlobalScope.launch {
                if(context != null) {
                    val db = Room.databaseBuilder(context, AppDatabase::class.java, "data").build()
                    val user = db.userDao().getAll()[position]
                    var text = "$user?.firstName $user?.lastName"
                    Toast.makeText(context, text, Toast.LENGTH_LONG).show()
                }
            }
        }

        return binding.root
    }
}

SecondFragment.kt

class SecondFragment : Fragment() {
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        val binding = FragmentSecondBinding.inflate(inflater, container, false)

        binding.button.setOnClickListener {
            val context = this.context
            GlobalScope.launch(Dispatchers.IO) {
                if(context != null) {
                    println("start insert")
                    val db = Room.databaseBuilder(context, AppDatabase::class.java, "data").build()

                    val id = binding.editNumber.text.toString().toInt()
                    val firstName = binding.editFirstName.text.toString()
                    val lastName = binding.editLastName.text.toString()
                    val user = User(id, firstName, lastName)

                    db.userDao().insert(user)
                    println("end insert -> user: $user")
                }
            }
            findNavController().navigate(R.id.action_SecondFragment_to_FirstFragment)
        }

        return binding.root
    }
}

fragment_first.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/list_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".FirstFragment">

    <ListView android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/white"
        android:layout_weight="1"
        android:drawSelectorOnTop="false"
        tools:listitem="@layout/list_item" />

</androidx.constraintlayout.widget.ConstraintLayout>

list_item

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="8dp"
    android:paddingRight="8dp">

    <TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/frame"
        android:fontFamily="serif"
        android:text="No data"
        android:textAlignment="center"
        android:textSize="20sp"
        android:textStyle="bold" />

</LinearLayout>

AppDatabase.kt

@Database(entities = [User::class], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao
}

UserData.kt

@Dao
interface UserDao {
    @Query("SELECT * FROM user")
    suspend fun getAll(): List<User>

    @Query("SELECT * FROM user WHERE first_name LIKE :first AND last_name LIKE :last LIMIT 1")
    suspend fun findByName(first: String, last: String): User

    @Insert
    suspend fun insert(user: User)

    @Update
    suspend fun update(user: User)

    @Delete
    suspend fun delete(user: User)
}

User.kt

@Entity
data class User(@PrimaryKey val uid: Int, @ColumnInfo(name = "first_name") val firstName: String? = null, @ColumnInfo(name = "last_name") val lastName: String? = null)


Solution 1:[1]

Don't create multiple room db instances in your code.first make it has singleton then do the whatever want to perform either insert or select.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 BabaVarma