'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 |
