Home > Software design >  How to return data from inside of addOnSuccessListener{} method in Kotlin?
How to return data from inside of addOnSuccessListener{} method in Kotlin?

Time:07-02

I am trying to get user data from Firebase Firestore database , I am intended to get info of user who is currently logged in. Now for make this information accessible from other Classes I created get method for username and email,

when I used get method from Another class , I got an indexOutOfBoundsException with index 0,size 0. It looks like my array in global scope is not getting data when i called array.add() method from addOnSuccessListener method.

package com.example.myapplication.utils

import android.os.Build
import androidx.annotation.RequiresApi
import com.example.myapplication.models.User
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.firestore.FirebaseFirestore

class UserInfo {
private val list = ArrayList<User>()
private val mFireStore = FirebaseFirestore.getInstance()


private fun getCurrentUserId(): String {
    val currentUser = FirebaseAuth.getInstance().currentUser
    var currentUserID = ""

    if (currentUser != null) {
        currentUserID = currentUser.uid
    }
    return currentUserID
}


@RequiresApi(Build.VERSION_CODES.R)
fun getUsername(): String {
    getCurrentUser()
    return list[0].userName
}


@RequiresApi(Build.VERSION_CODES.R)
fun getEmail(): String {
    getCurrentUser()
    return list[0].email
}


@RequiresApi(Build.VERSION_CODES.R)
private fun getCurrentUser() {
    mFireStore.collection(Constants.USERS)
        .document(getCurrentUserId())
        .get()
        .addOnSuccessListener { document ->
            val user = document.toObject(User::class.java)
            if (user != null) {
                list.add(user)
            }
        }
        .addOnFailureListener {
            TODO()
        }
}

}

CodePudding user response:

You can do this by using either callbackFlows or RxJava. I prefer callbackFlows.

//This Needs to be a suspending function
    private suspend fun getCurrentUser() = callbackFlow<User>{
        firestore.collection(Constants.USERS)
            .document(getCurrentUserId())
            .get()
            .addOnSuccessListener { document ->
                val user = document.toObject(User::class.java)
                if (user != null) {
                    list.add(user)
                    //Sends the data on cold Flow or Channel Flow
                    trySend(user)
                }
            }
            .addOnFailureListener {
                TODO()
            }
        
        awaitClose {
         // suspends the current coroutine until the channel is either closed or canceled and invokes the given block before resuming the coroutine.
      }
    }

trySend is where you send the data.

Also, awaitClose is required.

Furthermore, from wherever you call this function, you need to collect it, or else it won't work cold flows require an active collector to work.

You can do this by simply,

private suspend fun collectCurrentUser() {
  getCurrentUser().collect { data->
    // Use Data
  }
}

You can follow the following documentation: https://developer.android.com/kotlin/flow

CodePudding user response:

You can use Kotlin Unit function to return list

 private fun getCurrentUser(listener:(ArrayList<User>())->Unit){
       mFireStore.collection(Constants.USERS)
           .document(getCurrentUserId())
           .get()
           .addOnSuccessListener { document ->
              val user = document.toObject(User::class.java)
              if (user != null) {
                  list.add(user)
                 }
              listener.invoke(list)
             }
          .addOnFailureListener {
              TODO()
            }
    }

Now you can this method as below

getCurrentUser(){list->

}
  • Related