skip to Main Content

I’ve been building an app that allows the user to retrieve and delete some of his own itens registered on Firebase Database, that is my function that allows that (Thanks, Zeeshan):

override suspend fun getAllOnline(): MutableStateFlow<ResourceState<List<DocModel>>> {
    auth = FirebaseAuth.getInstance()
    val docList: MutableList<DocModel> = suspendCoroutine { continuation ->
        database
            .child(auth.currentUser!!.uid)
            .addValueEventListener(object : ValueEventListener {
                override fun onDataChange(snapshot: DataSnapshot) {
                    val docList: MutableList<DocModel> = mutableListOf()
                    for (docs in snapshot.children) {
                        val doc = docs.getValue(DocModel::class.java)
                        docList.add(doc!!)
                    }
                    continuation.resume(docList) << Line 34 where the error happens
                }

                override fun onCancelled(error: DatabaseError) {
                    continuation.resume(emptyList<DocModel>() as MutableList<DocModel>)
                }
            })
    }
    return if (docList.isNotEmpty()) {
        MutableStateFlow(ResourceState.Success(docList))
    } else {
        MutableStateFlow(ResourceState.Empty())
    }
}

The problem is that I’m not able to delete a file without the app crashing. The error thrown is:

2023-01-01 19:45:12.816 5637-5637/com.tods.docreminder E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.tods.docreminder, PID: 5637
java.lang.IllegalStateException: Already resumed
    at kotlin.coroutines.SafeContinuation.resumeWith(SafeContinuationJvm.kt:44)
    at com.tods.docreminder.feature.doc.data.repository.remote.DocFirebaseRepositoryImpl$getAllOnline$docList$1$1.onDataChange(DocFirebaseRepositoryImpl.kt:34)
    at com.google.firebase.database.core.ValueEventRegistration.fireEvent(ValueEventRegistration.java:75)
    at com.google.firebase.database.core.view.DataEvent.fire(DataEvent.java:63)
    at com.google.firebase.database.core.view.EventRaiser$1.run(EventRaiser.java:55)
    at android.os.Handler.handleCallback(Handler.java:942)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loopOnce(Looper.java:201)
    at android.os.Looper.loop(Looper.java:288)
    at android.app.ActivityThread.main(ActivityThread.java:7844)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)

As I understood, the problem is that I’m deleting something from web and It’s not updating realtime, so it’s not able to display the changes on my recycler view (the item is deleted using swipe, so the UI should update it automatically to show the new result to the user).
How would I be able to implement this realtime update from this function?
Any needed code, just tell me and I’ll update it asap.
Thanks for your support.

2

Answers


  1. Chosen as BEST ANSWER

    Thanks, Alex! I used this repository as example: repository.
    This is the updated result of the repository:

    override suspend fun getAllOnline(): MutableStateFlow<ResourceState<List<DocModel>>> {
        auth = FirebaseAuth.getInstance()
        val docList = mutableListOf<DocModel>()
        val docs = database.child(auth.currentUser!!.uid).get().await()
        for(document in docs.children) {
            val doc = document.getValue(DocModel::class.java)
            docList.add(doc!!)
        }
        return if (docList.isNotEmpty()) {
            MutableStateFlow(ResourceState.Success(docList))
        } else {
            MutableStateFlow(ResourceState.Empty())
        }
    }
    

    Now that I'm able to delete, I'll manage the exceptions properly using the Resource State message to send the answer to the user.

    Edited:
    Now receiving the exception:

    override suspend fun getAllOnline(): MutableStateFlow<ResourceState<List<DocModel>>> {
        auth = FirebaseAuth.getInstance()
        val docState: MutableStateFlow<ResourceState<List<DocModel>>>
        val docList = mutableListOf<DocModel>()
        docState = try {
            val docs = database.child(auth.currentUser!!.uid).get().await()
            for(document in docs.children) {
                val doc = document.getValue(DocModel::class.java)
                docList.add(doc!!)
            }
            if(docList.isNotEmpty()) {
                MutableStateFlow(ResourceState.Success(docList))
            } else {
                MutableStateFlow(ResourceState.Empty())
            }
        } catch(e: StorageException) {
            MutableStateFlow(ResourceState.Error(e.message))
        }
        return docState
    }
    

    And my ResourceState class if it helps:

    sealed class ResourceState<T>(
        val data: T? = null,
        val message: String? = null
    ) {
        class Success<T>(data: T?): ResourceState<T>(data)
        class Error<T>(message: String?, data: T? = null): ResourceState<T>(data, message)
        class Loading<T>: ResourceState<T>()
        class Empty<T>: ResourceState<T>()
    }
    

    Hope it helps =)


  2. the error comes from this line of code:

     continuation.resume(docList) << Line 34 where the error
    

    Coroutines are oneShot resume , so if you receive data you resume the first time, second time it will crash, Use Flow or Channel to receive multiple responses

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search