Hello I am having trouble with a problem where on my recycler view it displays sometimes the associated items given in the view. I had this problem earlier and what seem to make it work for the first couple of times was changing it from setImageResource to using setImageDrawable.
I think to fix this problem there is something wrong with adapter since I found out by printing the data that was in the list that there was nothing wrong with generateList() function but in the Adapter class sometimes when it is created the onBindViewHolder() class isn't ran.
Here is my code
package com.example.habittracker.recyclerview.Adapter
import android.content.Context
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import com.example.habittracker.R
import com.example.habittracker.recyclerview.Models.FFItem
import androidx.appcompat.app.AppCompatActivity
class Adapter(val context: Context,val elements: MutableList<FFItem>):
RecyclerView.Adapter<Adapter.FFViewHolder>(){
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): FFViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.file_explorer_view,parent,false)
return FFViewHolder(view)
}
override fun onBindViewHolder(
holder: FFViewHolder,
position: Int
) {
val currentItem = elements[position]
Log.i("TAG", "currentItem: "+currentItem.toString())
holder.title.text = currentItem.title
if(currentItem.folderId==null){
Log.i("TAG", "this is for a file")
var a = holder.img.resources.getDrawable(R.drawable.binary_digits,null)
holder.img.setImageDrawable(a)
holder.button.setOnClickListener {
Log.i("TAG", "you have clicked on a button to test for file")
}
}else{
//val drawable = ContextCompat.getDrawable(context, R.drawable.greenbackgroundmidshade)
//holder.img.setImageDrawable(drawable)
//holder.img.setImageResource(R.drawable.folder)
var a = holder.img.resources.getDrawable(R.drawable.folder,null)
holder.img.setImageDrawable(a)
Log.i("TAG", "this is for a folder")
holder.button.setOnClickListener {
var recyclerView: RecyclerView
//holder.v.findViewById<>()
// recyclerView = findViewById(R.id.recyclerView)
// recyclerView.adapter = adapter
//Log.i("TAG", "you have clicked on a button to test for folder")
}
}
}
override fun getItemCount(): Int {
return elements.size
}
inner class FFViewHolder(view: View) : RecyclerView.ViewHolder(view){
val v: View = view
val img: ImageView = view.findViewById(R.id.FileExplorerImageView)
val title: TextView = view.findViewById(R.id.FileExplorerTitle)
val button: Button = view.findViewById(R.id.FileExplorerButton)
}
}
package com.example.habittracker
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.habittracker.db.HabitTrackerDatabase
import com.example.habittracker.recyclerview.Adapter.Adapter
import com.example.habittracker.recyclerview.Models.FFItem
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
class Home : AppCompatActivity() {
lateinit var recyclerView: RecyclerView
lateinit var adapter: Adapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home)
var exampleList = generateList()
while(exampleList==null){
exampleList = generateList()
}
adapter = Adapter(this,exampleList)
recyclerView = findViewById(R.id.recyclerView)
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.setHasFixedSize(true)
}
public fun generateList(): MutableList<FFItem>{
val list = mutableListOf<FFItem>()
CoroutineScope(Dispatchers.IO).launch {
val db = HabitTrackerDatabase.getInstance(applicationContext).Dao()
//Log.i("TAG",db.getTotalCountFolder().toString())
for (i in 1 until db.getTotalCountFolder()+1) {
if(db.getInstanceFolderById(i).parentFolderId==null){
list.add(FFItem(db.getInstanceFolderById(i).name,null,i))
}
//list.add(FFItem("Title $i", "Description $i"))
}
for (i in 1 until db.getTotalCountFile()+1) {
if (db.getInstanceFileById(i).parentFolderId == null) {
list.add(FFItem(db.getInstanceFileById(i).name, i, null))
}
}
Log.i("TAG",list.toString())
}
return list
}
}
Ok. Let's start at the top:
var exampleList = generateList() while(exampleList==null){ exampleList = generateList() }
That's wrong. Your generateList function creates a list then launches a coroutine to generate the data. It will never return null. The check is not needed
Secondly- its creating the data on a coroutine. That's fine. But adding the data to the list isn't sufficient to update the adapter. You need to tell the adapter that a new item was added. This is done by calling one of the notifyDataSetChanged(), notifyDataSetInserted(), etc functions on the layout manager. When that's called, the recycler view will get notified the size of the Adapter has changed and will start considering the new items. Until then, it assumes the list is the same and will not query again. Since the list is being populated on a coroutine, what items will appear in the list is a race condition between the recycer view drawing for the first time and the coroutine generating data. Adding the notify calls would fix that.