Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle Activity.onActivityResult() with Jetpack Compose?

I am trying to implement sign-in hints in my Android app using Jetpack Compose, but this API requires an Activity to work.

fun showPhoneNumberHint(activity: Activity) {
    val hintRequest: HintRequest = HintRequest.Builder()
        .setPhoneNumberIdentifierSupported(true)
        .build()

    val intent = Auth.CredentialsApi.getHintPickerIntent(apiClient, hintRequest)
    val requestCode = 12345

    try {
        startIntentSenderForResult(activity, intent.intentSender, requestCode, null, 0, 0, 0, null)
    } catch (exception: SendIntentException) {
        // Error handling
    }
}

So I guess that I'll have to pass the Activity object all the way down to the Composable where it's needed, which doesn't seem very clean but it should work.

But now the result of the hint will be received in the Activity's onActivityResult() and I'm not sure what the right way is to get it back to the Composable where it's needed.

Is there some clean/standard/alternative way to do this? Preferably I'd just keep all of this logic contained inside the Composable.

like image 854
Duncan Luk Avatar asked Apr 20 '21 10:04

Duncan Luk


People also ask

How do I pass onActivityResult from activity to fragment?

Since Activity gets the result of onActivityResult() , you will need to override the activity's onActivityResult() and call super. onActivityResult() to propagate to the respective fragment for unhandled results codes or for all.

How do you observe state in Jetpack Compose?

The general pattern for state hoisting in Jetpack Compose is to replace the state variable with two parameters: value: T : the current value to display. onValueChange: (T) -> Unit : an event that requests the value to change, where T is the proposed new value.

How can I get result from startActivityForResult?

The android startActivityForResult method, requires a result from the second activity (activity to be invoked). In such case, we need to override the onActivityResult method that is invoked automatically when second activity returns result.


1 Answers

I ended up using rememberLauncherForActivityResult in combination with the ActivityResultContracts.StartIntentSenderForResult() contract to listen for the result. This returns a launcher that can be used to start the intent.

Instead of Auth.CredentialsApi, which requires the deprecated GoogleApiClient, I'm now using the Credentials.getClient. For this I still needed an Activity which I got using LocalContext.current.

val phoneNumberHintLauncher = rememberLauncherForActivityResult(
    contract = ActivityResultContracts.StartIntentSenderForResult()
) {
    if (it.resultCode != RESULT_OK) {
        return@rememberLauncherForActivityResult
    }

    val credential: Credential? = it.data?.getParcelableExtra(Credential.EXTRA_KEY)
    val hintResult = credential?.id

    if (hintResult !== null) {
        phoneNumber = hintResult
    }
}

val context = LocalContext.current

LaunchedEffect(Unit) {
    val hintRequest: HintRequest = HintRequest.Builder()
        .setPhoneNumberIdentifierSupported(true)
        .build()

    val phoneNumberHintIntent = Credentials.getClient(context)
        .getHintPickerIntent(hintRequest)

    phoneNumberHintLauncher.launch(
        IntentSenderRequest.Builder(phoneNumberHintIntent)
            .build()
    )
}
like image 180
Duncan Luk Avatar answered Oct 13 '22 03:10

Duncan Luk