Search code examples
androidkotlingoogle-cloud-firestorekotlin-coroutinescoroutinescope

How to use continues instead of bad callbacks


I get data from Firestone , Because do not want empty list to be return ,I use callbacks is coroutine better , I have a lot of this so call back is noisy for this case , is async/await will be a good solution

         getHerosFromCloud(object :OnFinishedCallbacks {
             override fun onFinshed(list: List<Any>) {
                 CoroutineScope(Dispatchers.IO).launch {
                     MainDatabase.heroDao.insertAll(*(list as List<Hero>).toTypedArray())

                 }
             }
         })


interface OnFinishedCallbacks {
    fun onFinshed( list:List<Any>)
}


 fun getHerosFromCloud(onFinishedCallbacks: OnFinishedCallbacks)
        {

            val heroList =ArrayList<Hero>()

                   db.collection("Heros")
                .get()
                .addOnSuccessListener { documentSnapshot  ->
                    if (documentSnapshot  != null) {
                        for(heroDoc in documentSnapshot) {
                            heroList.add(heroDoc.toObject(Hero::class.java))
                        }

                        Log.d("newherosNames", "newdoorsNames data: ${heroList}")
                        onFinishedCallbacks.onFinshed(heroList)
                    } else {
                        Log.d("heros", "No such document")
                    }
                }
                .addOnFailureListener { exception ->
                    Log.d("heros", "get failed with ", exception)
                }

        }

Solution

  • As I understand you want to make your code more clean and consistent when using callback Api. You can use suspendCoroutine or suspendCancellableCoroutine.

    suspendCoroutine suspends coroutine in which it executed until we decide to continue by calling appropriate methods - Continuation.resume....

    suspendCancellableCoroutine function, it behaves similar to suspendCoroutine with additional feature - provides an implementation of CancellableContinuation to the block.

    For your example it will look something like this:

    suspend fun getHeroesFromCloud() = suspendCoroutine<List<Hero>> { continuation ->
        db.collection("Heros")
            .get()
            .addOnSuccessListener { documentSnapshot  ->
                val heroList = ArrayList<Hero>()
                if (documentSnapshot  != null) {
    
                    for(heroDoc in documentSnapshot) {
                        heroList.add(heroDoc.toObject(Hero::class.java))
                    }
    
                    Log.d("newherosNames", "newdoorsNames data: ${heroList}")
                } else {
                    Log.d("heros", "No such document")
                }
                continuation.resume(heroList)
            }
            .addOnFailureListener { exception ->
                continuation.resumeWithException(exception)
                Log.d("heros", "get failed with ", exception)
            }
    
    }
    
    // Call this function from a coroutine
    suspend fun someFun() {
        val heroes = getHeroesFromCloud()
        // use heroes
    }