Save result of async method in variable in Kotlin

Viewed 502

I tried to store a result from an async Kotlin method to a variable.

        Amplify.Auth.fetchAuthSession(
            {result ->
                Log.i(TAG, "Amplify: Fetch Auth Session $result")
                isAuthenticated = result.isSignedIn
            },
            {error ->
                Log.e(TAG , "Amplify: Fetch Auth Session $error")
            }
        )
        

        if (isAuthenticated == true) {
[...]

I really don't know how to set the result.isSignedIn to the isAuthenticated variable, that I can use it outside of the closure. I found a similar question on stackoverflow, but it did not help me out.

May someone can help me?!

2 Answers

What are you doing here (in terms of saving the value within the lambda) is technically correct, but functionally - not necessarily: the value is used before it is updated by the lambda.

Consider starting the further logic from the callback lambda, where you receive the result.

Please see the snippet below for a better overview:

        Amplify.Auth.fetchAuthSession(
            {result ->
                Log.i(TAG, "Amplify: Fetch Auth Session $result")
                handleResult(result.isSignedIn)
            },
            {error ->
                Log.e(TAG , "Amplify: Fetch Auth Session $error")
            }
        )
    } // end of the method with the async call

    fun handleResult(isAuthenticated: Boolean) {
        // here goes the code that consumes the result
        if (isAuthenticated) {
            // ...
        }
    }

I'm not sure whether this is the best practice, but it is something that worked out for me in terms of code readability and functionality when it comes to async functions.
Say you have an async function doSomethingAsync. If I need it to be completed before following through with other instructions (such as your if statement), I pass on 1 or more functions to the async function, with each function covering a certain scenario.
What I mean by this is the following:

    fun doSomethingAsync() (
        onSuccess : (fetchedObject : Any) -> Unit,   // Do stuff with returned value
        onFailure : (e : Exception) -> Unit,  // Catch an exception
        onComplete : () -> Unit  // Do stuff after the value has been fetched
    ) {
        // Your async function body, which could return a Task
        .addOnSuccessListener { result ->
            onSuccess(result)
            onComplete()
    }
        .addOnFailureListener { exception -> 
            onFailure(exception)
    }
}

In your case, you could fit your if statement and stuff that follows into a function, which you could pass onto the async function as a function parameter, to be called after the async task is complete.

        Amplify.Auth.fetchAuthSession(onComplete : () -> Unit)
        {result ->
            Log.i(TAG, "Amplify: Fetch Auth Session $result")
            isAuthenticated = result.isSignedIn
            onComplete()
        },
        {error ->
            Log.e(TAG , "Amplify: Fetch Auth Session $error")
        }
    )
    
    fun onComplete() {
         // Assume that ifAuthenticated == true, and call this after 
         // you get the Auth results.
    }
Related