Ideas to get a call back/promise/fufillment type thing from an Async Backendless Method

Hi Backendless. Not really a backendless question, but I just can’t get this to do what I want. (forgive me not a full time Android dev!)

I have a suspend function in a kotlin class. To keep things concise it is something like this

suspend fun backendlessRequest()  {

        val dataQuery = DataQueryBuilder.create()
        var queryBuilder = LoadRelationsQueryBuilder.of(BackendlessUser::class.java)
        queryBuilder.setRelationName("leaderOf")

        val parentObjectId: String = "xxxxx"
        val dataStore = Backendless.Data.of("Users")

        dataStore.loadRelations(parentObjectId,queryBuilder,
                object : AsyncCallback<List<BackendlessUser?>> {
                    override fun handleResponse(foundUsers: List<BackendlessUser?>?) {
                       /* users successfully returned here.
                          but how can I advise the calling class that this has now been done?
                          bit like a 'fulfill' in PromiseKit Swift
                       */
                    }

                    override fun handleFault(fault: BackendlessFault?) {
                        /* and how could I tell calling class that there was a problem?
                        */
                    }
                }) 
}

Now from another class I call this sucessfully

  fun callBackendlessRequest(){
     
        scope.launch(Dispatchers.Main){

             val done = async(Dispatchers.IO) {
                    theOtherClass.backendlessRequest()
              }

         done.await()!!

         /* now I want to wait here, until I have fulfilled the backendless request
          understandably the code does not wait

          I want to use the async backendless code, but do not want to put code
         in the handlessResponse in the callback 

         but put it here, but how can I do this? (I can achive this using promiseKit in Swift)

         */


        }

I hope this makes sense. I know not strictly a backendless question, but any help or ideas to put me on the right lines would be great backendless team!!

Hi, @mike-turner

We are looking into your problem, will get back when we find any solution for you.

Regards,
Serhiy

any update on this ?

Hi Mike,

I posted your question to chatgpt and here’s it’s response:

To adapt the loadRelations call to work seamlessly with Kotlin coroutines and achieve the desired behavior, you can use the suspendCancellableCoroutine function. This allows you to wrap the asynchronous callback into a coroutine-friendly suspend function. Here’s how you can adjust your backendlessRequest function:

import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException

suspend fun backendlessRequest(): List<BackendlessUser?> {
return suspendCancellableCoroutine { continuation →
val dataQuery = DataQueryBuilder.create()
val queryBuilder = LoadRelationsQueryBuilder.of(BackendlessUser::class.java)
queryBuilder.setRelationName(“leaderOf”)

    val parentObjectId: String = "xxxxx"
    val dataStore = Backendless.Data.of("Users")

    dataStore.loadRelations(parentObjectId, queryBuilder, object : AsyncCallback<List<BackendlessUser?>> {
        override fun handleResponse(foundUsers: List<BackendlessUser?>?) {
            // Resume the coroutine with the result
            continuation.resume(foundUsers ?: emptyList())
        }

        override fun handleFault(fault: BackendlessFault?) {
            // Resume the coroutine with an exception
            continuation.resumeWithException(
                fault?.let { Exception(it.message) } ?: Exception("Unknown error")
            )
        }
    })

    // Handle coroutine cancellation
    continuation.invokeOnCancellation {
        // Perform any cleanup if necessary
    }
}

}

Now, in your calling function, you can await the result of backendlessRequest():

fun callBackendlessRequest() {
scope.launch(Dispatchers.Main) {
try {
val result = withContext(Dispatchers.IO) {
theOtherClass.backendlessRequest()
}
// Use the result here
println(“Users: $result”)
} catch (e: Exception) {
// Handle the error
println(“Error: ${e.message}”)
}
}
}

Explanation:

  1. suspendCancellableCoroutine: Converts the callback-based loadRelations method into a coroutine-friendly suspend function.

  2. Error Handling: The handleFault callback maps to an exception, allowing you to use try-catch in the coroutine scope.

  3. withContext(Dispatchers.IO): Ensures the backendlessRequest runs on a background thread.

This approach allows your calling code to wait for the asynchronous operation to complete in a coroutine-friendly manner, while keeping your logic centralized and readable.

<<<<
Hope this helps

Regards,
Mark

hmm. interesting, will give it a go. Thanks Mark