tore
tore

Reputation: 689

How does Firebase completion callbacks work in Kotlin

I have successfully read data from Firebase and displayed it in an imageView asynchronously using a completion callback. Being new to programming, I'm still having a hard time understanding some of the mechanisms around callbacks and hope someone would be kind to shed some light to some of my questions. I have already read and watched multiple tutorials and explanations, but still struggle understanding some concepts. Here is my Firebase code:

Part 1:

readFirebaseData(object: FirebaseCallback{
        override fun onCallback(list: MutableList<RecipeTemplate>) {

            glideVariable?.loadImageUrl(recipeArray[1].recipeImage) //WORKS!!
        }
})

Part 2:

fun readFirebaseData(firebaseCallback: FirebaseCallback) {
    ref!!.addValueEventListener(object: ValueEventListener {
        override fun onDataChange(snapshot: DataSnapshot?) {

            for (item in snapshot!!.children) {
                var tempRecipe = RecipeTemplate()
                val image = item.child("recipeImageFirebase")

                tempRecipe.recipeImage = image.value.toString()
                recipeArray.add(tempRecipe)
            }
            //INSERTING CODE HERE AT LATER STAGE... SEE LATER IN POST
            firebaseCallback.onCallback(recipeArray)

        }//END ON DATA CHANGE METHOD
    }) //END FB
}//END READ DATA

Part 3:

interface FirebaseCallback {
    fun onCallback(list: MutableList<RecipeTemplate>)
}

The main thing is that I don't understand the point of the interface, and the whole override function-part (PART 1). Thing is, I successfully did the very same thing just using a function call at the end of the Firebase code. It requires way less code and is easier to follow and understand, and from what I can tell, it does the same thing. It looks like this:

Inside PART 2:

test(recipeArray) //SIMPLY CALLING A FUNCTION INSTEAD OF THE CODE PREVIOUSLY USED.
//firebaseCallback.onCallback(recipeArray)

Then the test function itself:

 fun test(list: MutableList<RecipeTemplate>) {
    Log.d("TAGM", "DONE WITH FB")
    glideVariable?.loadImageUrl(recipeArray[3].recipeImage)    
}

So, what am I missing here? Why use the whole interface callback thing?

Upvotes: 0

Views: 1165

Answers (1)

Alex Mamo
Alex Mamo

Reputation: 138824

To solve this, you need to create your own callback to wait for Firebase to return you the data. To achieve this, first you need to create an interface like this:

interface FirebaseCallback {
    fun onCallback(list: MutableList<RecipeTemplate>)
}

Then you need to create a function that is actually getting the data from the database. This function should look like this:

fun readFirebaseData(firebaseCallback: FirebaseCallback) {
    ref.addListenerForSingleValueEvent(object : ValueEventListener {
        override fun onDataChange(dataSnapshot: DataSnapshot) {
            val list = ArrayList<RecipeTemplate>()
            for (ds in dataSnapshot.getChildren()) {
                val recipeTemplate = ds.getValue(RecipeTemplate::class.java!!)
                list.add(recipeTemplate)
            }
            firebaseCallback.onCallback(list)
        }

        override fun onCancelled(databaseError: DatabaseError) {}
    })
}

In the end just simply call readData() function and pass an instance of the FirebaseCallback interface as an argument wherever you need it like this:

readFirebaseData(object : FirebaseCallback {
    override fun onCallback(list: MutableList<RecipeTemplate>) {
        //Do what you need to do with your list
    }
})

This is the only way in which you can use that value outside onDataChange() function.

Upvotes: 2

Related Questions