2

I am new to Android and Kotlin and I want to implement a FirebaseRetriever class in my project that returns a specific database snapshot.

Now I am having issues that the EventListener is never triggered and so, of course, I get a null object back.

Here is my data class:

public class FirebaseRetriever() {

    private val TAG = "FirebaseRetriever"
    private lateinit var fbData: FirebaseDatabase
    private lateinit var fbAuth: FirebaseAuth
    private lateinit var userRef: DatabaseReference
    //Snapshots
    private lateinit var userSnap: DataSnapshot

    init {
        fbData = FirebaseDatabase.getInstance()
        userRef = fbData.reference.child("users")
        fbAuth = FirebaseAuth.getInstance()

        userRef.addValueEventListener(object : ValueEventListener {
            override fun onCancelled(e: DatabaseError) {
                Log.e(TAG, "Data could not be retrieved from Database." + e.message)
            }

            override fun onDataChange(snap: DataSnapshot) { // is never executed
                userSnap = snap 
            }

        })
    }

    public fun getUserSnap(): DataSnapshot {
        return userSnap // returns null
    }
}

This is how I call the getUser():

firebaseRetriever = FirebaseRetriever()
...
val uniSnap = firebaseRetriever.getUniSnap()

Is it possible that a Firebase EventListener can only work in a regular AndroidActivity or am I doing something else wrong?

Thanks in advance.

1 Answers1

0

Most likely the data simply hasn't been loaded yet when you call getUserSnap. To verify this, add a few more log statements:

Log.i(TAG, "Starting to read from database.")

userRef.addValueEventListener(object : ValueEventListener {
    override fun onCancelled(e: DatabaseError) {
        Log.e(TAG, "Data could not be retrieved from Database." + e.message)
    }

    override fun onDataChange(snap: DataSnapshot) { // is never executed
        Log.i(TAG, "User read from database.")
        userSnap = snap 
    }

})

public fun getUserSnap(): DataSnapshot {
    Log.i(TAG, "Getting user.")
    return userSnap // returns null
}

When you run your app with this the output will likely be:

Starting to read from database.

Getting user.

User read from database.

That is probably not the order you expected. Firebase loads data from the database asynchronously, since it may take some time for the results to be available. Instead of making your app wait (which would trigger an Application Not Responding dialog), your code is allowed to continue. Bu the time you call getUserSnap, that user hasn't been loaded yet.

The simplest solution is to move all the code that needs access to the user into the onDataChange() method. Also see my answer to this question for a more flexible solution, that requires more code: getContactsFromFirebase() method return an empty list

Community
  • 1
  • 1
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807