I'm trying to populate a mutable list so that I can use it for a recycler view. Unfortunately, although (i think) I'm populating the list, it's still remaining empty and the recycler view is not working (and I imagine it's because of the list issue). Please see below for the code:
private val newList: MutableList<NewListModel> = mutableListOf()
private val oldList = retrieveOldList()
private fun retrieveAndPopulate() {
for (i in 0 until oldList.size){
val oldItem = oldList[i]
val itemOne = oldItem.itemOne
val itemTwo = oldItem.itemTwo
val itemThree = oldItem.itemThree
val itemFour = oldItem.itemFour
val newItemData =
NewListModel(
itemOne, itemTwo, itemThree, itemFour
)
newList.add(newItemData)
Log.d(
"RetrieveData",
"${newItemData.itemOne} has been added to the list."
)
}
}
The class below is for the "NewListModel"
@Keep
@IgnoreExtraProperties
data class NewListModel (
var itemOne: String ?= null,
var itemTwo: String ?= null,
var itemThree: String ?= null,
var itemFour: String ?= null,
)
Below is how i try to populate the "oldList"
fun retrieveData(): MutableList<OldListModel> {
val list: MutableList<OldListModel> = mutableListOf()
val ref = FirebaseDatabase.getInstance().getReference("/storage")
ref.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists()) {
ref.get()
.addOnSuccessListener {
for (listItem in snapshot.children) {
val listItem = snapshot.getValue(OldListModel::class.java)
if (listItem != null) {
list.add(listItem)
}
}
}
} else {
Log.d(
"Data",
"Retrieving data was unsuccessful."
)
}
}
override fun onCancelled(error: DatabaseError) {
}
})
return list
}
It's probably worth mentioning that I'm getting the data from one mutable list and adding it to another. Any help is much appreciated
(below is how i try to populate the recycler view)
val newList = retrieveAndPopulate()
val recyclerView = findViewById<View>(R.id.recyclerView) as RecyclerView
val layoutManager = LinearLayoutManager(this)
recyclerView.layoutManager = layoutManager
val adapterAdapter = AdapterAdapter(newList)
recyclerView.adapter = adapterAdapter
CodePudding user response:
Your problem is that you think you're running code sequentially when it's running asynchronously. See the numbered comments from your function to trace the order of execution:
fun retrieveData(): MutableList<OldListModel> {
// 1. Here you create a list
val list: MutableList<OldListModel> = mutableListOf()
val ref = FirebaseDatabase.getInstance().getReference("/storage")
// 2. Here a listener is added that will let you know LATER when the data is ready
ref.addValueEventListener(object : ValueEventListener {
// 4. LATER the data changed will get called
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists()) {
ref.get()
.addOnSuccessListener {
// 5. EVEN LATER this listener is called with data
for (listItem in snapshot.children) {
val listItem = snapshot.getValue(OldListModel::class.java)
// 6. FINALLY - you add to a list that has long since stopped being relevant
if (listItem != null) {
list.add(listItem)
}
}
}
} else {
Log.d(
"Data",
"Retrieving data was unsuccessful."
)
}
}
override fun onCancelled(error: DatabaseError) {
}
})
return list // 3. Here you return the EMPTY list that was created
}
A solution - though likely not the best solution is to update your list once the callbacks complete:
fun retrieveData(): { // No longer returning anything
// Remove this, no longer returning anything
// val list: MutableList<OldListModel> = mutableListOf()
val ref = FirebaseDatabase.getInstance().getReference("/storage")
ref.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists()) {
ref.get()
.addOnSuccessListener {
// Move list here
val list: MutableList<OldListModel> = mutableListOf()
for (listItem in snapshot.children) {
val listItem = snapshot.getValue(OldListModel::class.java)
if (listItem != null) {
list.add(listItem)
}
}
// Since you're using Kotlin, you could use a map,
// but that's unrelated to this issue
// val list = snapshot.children.map { getValue(...) }.filterNotNull()
// Now that we have a full list here, update:
updateAdapterWithNewData(list)
}
} else {
Log.d(
"Data",
"Retrieving data was unsuccessful."
)
}
}
override fun onCancelled(error: DatabaseError) {
}
})
}
Where updateAdapterWithNewData
is a function you write to do as it says.
Please read up on asynchronous programming and make sure you understand how the code is flowing when using callbacks / listeners in frameworks like Firebase.