Home > Software design >  Data from Firebase Realtime Database is retreived, but not set when returned from a function?
Data from Firebase Realtime Database is retreived, but not set when returned from a function?

Time:12-26

I'm trying to get data from Firebase and return it as an array. So far this works, however the data remains to be the default data that I had set it.

Here is the code (I added a few comments to clarify where it works and where id doesn't):

fun getRandomQuestion() : ArrayList<ArrayList<String>>{
    val random = Random(1234567)
    val randQuestionId = random.nextInt(0, 27)

    var dataRequestResult : String = "empty"

    var requestSide1 : String = "empty"
    var requestSide2 : String = "empty"
    var requestCount1 : String = "empty"
    var requestCount2 : String = "empty"

    //Get a random question from the DB
    Firebase.database.reference.child(Constants.wyrDBQuestionLocation)
        .child(randQuestionId.toString())
        .get()
        .addOnFailureListener { task ->
            Log.i("Get WYR Question Status", "Failed: "   task.message.toString())
            requestSide1 = "empty"
            requestSide2 = "empty"
            requestCount1 = "empty"
            requestCount2 = "empty"
        }.addOnSuccessListener {
            Log.i("Get WYR Question Status", "Success")

            //Logging this data returns the correct information from firebase, no issue here
            Log.i("Request Data Result", it.value.toString())

            dataRequestResult = it.value.toString()
        }

    requestSide1 = dataRequestResult.substringAfter("side1Question=").substringBefore("}")
    requestSide2 = dataRequestResult.substringAfter("side2Question=").substringBefore(",")
    requestCount1 = dataRequestResult.substringAfter("sideCount1=").substringBefore(",")
    requestCount2 = dataRequestResult.substringAfter("sideCount2=").substringBefore(",")

    //Return the value
    return arrayListOf(arrayListOf(requestSide1, requestCount1), arrayListOf(requestSide2, requestCount2))
}

Activity where I try to get the returned value:

    val myQuestion = databaseController.getRandomQuestion()

    //This is where the issue lies
    //When I get the returned data from the function above, it gives me all of the defaults I had set in the function (which is "empty")
    //It logs:`[["empty", "empty"],["empty", "empty"]]`
    Log.i("My Question", myQuestion.toString())

The data in the success listener is correct, but the return value is still default. Here is an image of the logs:

Logs

"Request Log Result", don't mind the result, I'm making a WYR app.

I have noticed that the request from the listener had come last, not first

I think this had to do with the data not even being completely gathered yet because in another app I made, all i had to do was give it a delay and it would be set, but in this case, I have no idea what to do.

Any help would be greatly appreciated! :)

CodePudding user response:

this is my solution

Method 1

fun getRandomQuestion() : ArrayList<ArrayList<String>>{
    val random = Random(1234567)
    val randQuestionId = random.nextInt(0, 27)

    var dataRequestResult : String = "empty"

    var requestSide1 : String = "empty"
    var requestSide2 : String = "empty"
    var requestCount1 : String = "empty"
    var requestCount2 : String = "empty"

    //Get a random question from the DB
    Firebase.database.reference.child(Constants.wyrDBQuestionLocation)
        .child(randQuestionId.toString())
        .get()
        .addOnFailureListener { task ->
            Log.i("Get WYR Question Status", "Failed: "   task.message.toString())
            requestSide1 = "empty"
            requestSide2 = "empty"
            requestCount1 = "empty"
            requestCount2 = "empty"
        }.addOnSuccessListener {
            Log.i("Get WYR Question Status", "Success")

            //Logging this data returns the correct information from firebase, no issue here
            Log.i("Request Data Result", it.value.toString())

            dataRequestResult = it.value.toString()
    requestSide1 = dataRequestResult.substringAfter("side1Question=").substringBefore("}")
    requestSide2 = dataRequestResult.substringAfter("side2Question=").substringBefore(",")
    requestCount1 = dataRequestResult.substringAfter("sideCount1=").substringBefore(",")
    requestCount2 = dataRequestResult.substringAfter("sideCount2=").substringBefore(",")

        }

    
    //Return the value
    return arrayListOf(arrayListOf(requestSide1, requestCount1), arrayListOf(requestSide2, requestCount2))
}

Method 2

fun getRandomQuestion() : ArrayList<ArrayList<String>>{
    val random = Random(1234567)
    val randQuestionId = random.nextInt(0, 27)

    var dataRequestResult : String = "empty"

    var requestSide1 : String = "empty"
    var requestSide2 : String = "empty"
    var requestCount1 : String = "empty"
    var requestCount2 : String = "empty"

    //Get a random question from the DB
    Firebase.database.reference.child(Constants.wyrDBQuestionLocation)
        .child(randQuestionId.toString())
        .get()
        .addOnFailureListener { task ->
            Log.i("Get WYR Question Status", "Failed: "   task.message.toString())
            requestSide1 = "empty"
            requestSide2 = "empty"
            requestCount1 = "empty"
            requestCount2 = "empty"
        }.addOnSuccessListener {
            Log.i("Get WYR Question Status", "Success")

            //Logging this data returns the correct information from firebase, no issue here
            Log.i("Request Data Result", it.value.toString())

            dataRequestResult = it.value.toString()
    requestSide1 = dataRequestResult.substringAfter("side1Question=").substringBefore("}")
    requestSide2 = dataRequestResult.substringAfter("side2Question=").substringBefore(",")
    requestCount1 = dataRequestResult.substringAfter("sideCount1=").substringBefore(",")
    requestCount2 = dataRequestResult.substringAfter("sideCount2=").substringBefore(",")
//Return the value
    return arrayListOf(arrayListOf(requestSide1, requestCount1), arrayListOf(requestSide2, requestCount2))
        }

return null    
    
}

CodePudding user response:

The listeners you use when requesting database data will fire later than the getRandomQuestion function returns ArrayList. You can use Kotlin coroutines to work with callbacks and suspend a coroutine until callback is fired, for example:

suspend fun getRandomQuestion() = suspendCoroutine<String> { continuation ->
    Firebase.database.reference.child(Constants.wyrDBQuestionLocation)
    .child(randQuestionId.toString())
    .get()
    .addOnFailureListener { task ->
        continuation.resume("empty")
    }.addOnSuccessListener {
        continuation.resume(it.value.toString())
    }
}

// somewhere in your code (e.g. in ViewModel, Activity or Fragment):

someCoroutineScope.launch {
    val question: String = getRandomQuestion();
    // ... use question to update UI
}

In Activity or Fragment you can use lifecycleScope, in ViewModel - viewModelScope.

suspendCoroutine builder function is used to wait for the callbacks. suspendCoroutine suspends coroutine in which it executed until we decide to continue by calling appropriate methods - Continuation.resume....

  • Related