I want make a recursive call when if condition is true as you can see inside this method, but is does not work.
I tried to replace this getWordsRequestsCount()
not to be a callbackFlow, but my custom callback, but it gave no effect but anyway it is not probably a key here.
If you need anything more just ask me about it.
So, how to solve that? Thank you in advance.
fun getWordsRequests(motherTongue: String,
foreignLanguage: String,
userId: String,
isNextPortion: Boolean,
isToShowPb: MutableLiveData<Boolean>): Flow<ArrayList<WordLoader>> =
callbackFlow {
val ref = database.getReference("words_requests").child(motherTongue)
.child(foreignLanguage)
var postListener: ValueEventListener? = null
getWordsRequestsCount(motherTongue, foreignLanguage, userId).collect {
postListener = object : ValueEventListener {
val list = ArrayList<WordLoader>()
override fun onCancelled(error: DatabaseError) {
trySend(list)
isToShowPb.value = false
}
override fun onDataChange(dataSnapshot: DataSnapshot) {
if (it > 0) {
for (ds in dataSnapshot.children) {
if (ds.child("user_id").value != userId) {
val word = Word.prepare(ds, motherTongue, foreignLanguage)
val wordLoader = WordLoader(word)
list.add(wordLoader)
val isMore = Util.isMoreForMore(it, list.size)
wordLoader.isMore = isMore
val index = list.indexOf(wordLoader)
list[index] = wordLoader
}
}
isToShowPb.value = false
if (list.size < 2 && list.size < it) {
lastWordRequest += list.size
getWordsRequests(motherTongue, foreignLanguage, userId, isNextPortion, isToShowPb)
}
}
if (list.isNotEmpty()) {
val newLastAddingId = list.last().word.id!!.toDouble()
lastWordRequest = if (newLastAddingId > lastWordRequest) newLastAddingId else lastWordRequest
}
trySend(list)
list.clear()
}
}
if (isNextPortion) {
lastWordRequest++
}
ref.orderByChild("id").startAt(lastWordRequest)
.limitToFirst(TOTAL_ELEMENTS_IN_LIST + 1)
.addListenerForSingleValueEvent(postListener)
if (it == 0) {
clearValues()
isToShowPb.value = false
}
}
awaitClose {
ref.orderByChild("id").startAt(lastWordRequest)
.limitToFirst(TOTAL_ELEMENTS_IN_LIST + 1)
.addListenerForSingleValueEvent(postListener!!)
}
}
EDIT - minimal example
fun getWordsRequests(motherTongue: String,
foreignLanguage: String,
userId: String): Flow<ArrayList<WordLoader>> =
callbackFlow {
val ref = database.getReference("words_requests").child(motherTongue)
.child(foreignLanguage)
var postListener: ValueEventListener? = null
getWordsRequestsCount(motherTongue, foreignLanguage, userId).collect {
postListener = object : ValueEventListener {
val list = ArrayList<WordLoader>()
override fun onCancelled(error: DatabaseError) {
trySend(list)
}
override fun onDataChange(dataSnapshot: DataSnapshot) {
if (it > 0) {
for (ds in dataSnapshot.children) {
if (ds.child("user_id").value != userId) {
// ADDING TO LIST
}
}
if (list.size < 2 && list.size < it) {
getWordsRequests(motherTongue, foreignLanguage, userId)
}
}
trySend(list)
list.clear()
}
}
ref.orderByChild("id").startAt(lastWordRequest)
.limitToFirst(TOTAL_ELEMENTS_IN_LIST + 1)
.addListenerForSingleValueEvent(postListener)
}
awaitClose {
ref.orderByChild("id").startAt(lastWordRequest)
.limitToFirst(TOTAL_ELEMENTS_IN_LIST + 1)
.addListenerForSingleValueEvent(postListener!!)
}
}
Every call to getWordsRequests() creates new flow (with its own Firebase listener).
Calling it inside itself just creates another cold flow, it doesn’t magically continue emitting values into your current flow.
fun getWordsRequests(
motherTongue: String,
foreignLanguage: String,
userId: String,
isNextPortion: Boolean,
isToShowPb: MutableLiveData<Boolean>
): Flow<List<WordLoader>> = callbackFlow {
val ref = database.getReference("words_requests")
.child(motherTongue)
.child(foreignLanguage)
// launch a coroutine inside callbackFlow to handle recursive fetching
launch {
getWordsRequestsCount(motherTongue, foreignLanguage, userId).collect { totalCount ->
suspend fun fetchPortion(startId: Double) {
val list = mutableListOf<WordLoader>()
val listener = object : ValueEventListener {
override fun onCancelled(error: DatabaseError) {
trySend(emptyList())
isToShowPb.value = false
}
override fun onDataChange(snapshot: DataSnapshot) {
for (ds in snapshot.children) {
if (ds.child("user_id").value != userId) {
val word = Word.prepareAssociation(ds, motherTongue, foreignLanguage)
val wordLoader = WordLoader(word)
wordLoader.isMore = Util.isMoreForMore(totalCount, list.size + 1)
list.add(wordLoader)
}
}
if (list.isNotEmpty()) {
val newLastId = list.last().word.id!!.toDouble()
lastWordRequest = maxOf(lastWordRequest, newLastId)
}
// send to the flow
trySend(list.toList())
isToShowPb.value = false
// 🔁 Recursive part → call again if condition holds
if (list.size < 2 && list.size < totalCount) {
fetchPortion(lastWordRequest + 1)
}
}
}
ref.orderByChild("id")
.startAt(startId)
.limitToFirst(TOTAL_ELEMENTS_IN_LIST + 1)
.addListenerForSingleValueEvent(listener)
}
if (totalCount == 0) {
clearValues()
isToShowPb.value = false
trySend(emptyList())
} else {
if (isNextPortion) lastWordRequest++
fetchPortion(lastWordRequest)
}
}
}
awaitClose {
// nothing special to clean up here because we use singleValueEvent
}
}