pedja
pedja

Reputation: 3413

function parameter scope in suspend functions

So basically what is the function parameter scope in a suspend function, and is it ok to use activity in a suspend function that could in theory be suspended for a long time

For example:

suspend fun function(activity: Activity) = suspendCancellableCoroutine<SomeResult> { continuation ->
    Api.expecuteSomeRequest().onFinishListener { result ->
        //using activity here would be bad
        continuation.resume(result)
    }//for example this request could take a long time, activity could be destroyed by that point
    activity.doSomething() 
    //is using activity here ok, will activity parameter go out of scope after this is executed,
    //or will it wait for the whole suspend function to finish
}

real worl usage example:

suspend fun Activity.loginWithFacebook() = suspendCancellableCoroutine<AuthCredential> { continuation ->
    val callbackManager = CallbackManager.Factory.create()
    LoginManager.getInstance().registerCallback(callbackManager, object :
        FacebookCallback<LoginResult> {
        override fun onCancel() {
            continuation.resumeWith(Result.failure(...))
        }

        override fun onError(error: FacebookException) {
            continuation.resumeWith(Result.failure(error))
        }

        override fun onSuccess(result: LoginResult) {
            continuation.resumeWith(Result.success(FacebookAuthProvider.getCredential(result.accessToken.token)))
        }

    })
    LoginManager.getInstance().logInWithReadPermissions(this, callbackManager, listOf("public_profile"))
}

Upvotes: 1

Views: 301

Answers (1)

Tenfour04
Tenfour04

Reputation: 93739

It would only be okay if these suspend functions were called from a CoroutineScope that is cancelled when the Activity is destroyed, such as lifecycleScope. It would not be appropriate for a coroutine called from viewModelScope.

For something like your first example, I would remove the activity from the function entirely. Whatever you want to do with your Activity you can do in the activity’s own coroutine.

In the second example, your parameter probably only needs to be a Context. Typically when you pass a Context to an API, you should not pass an Activity, whether or not you’re using a coroutine. You can call applicationContext in your Activity to get a Context that you don’t have to worry about leaking.

However both of these functions that interact with UIs would likely benefit from being moved to a ViewModel and publishing to a Deferred or Flow property in the ViewModel. Then if someone opens an Activity that starts a login flow and then rotates the screen while it’s still working, they can still get the result in the new Activity without it having to start over.

Upvotes: 1

Related Questions