How does Firebase completion callbacks work in Kot

2019-08-19 15:32发布

问题:

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?

回答1:

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.