Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

rememberLauncherForActivityResult throws Launcher has not been initialized in Jetpack Compose

When trying to invoke the Firebase Auth UI, using the below code the compiler throws java.lang.IllegalStateException: Launcher has not been initialized. Not sure, why the launcher is not initialized

@Composable
internal fun ProfileUI(profileViewModel: ProfileViewModel) {
    val loginLauncher = rememberLauncherForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { result ->
        if (result != null) {
         //do something
        }
    }
    if (profileViewModel.isAnonymousUser) {
        loginLauncher.launch(profileViewModel.buildLoginIntent())

    } else {


    }
}

    override fun buildLoginIntent(): Intent {

    val authUILayout = AuthMethodPickerLayout.Builder(R.layout.auth_ui)
        .setGoogleButtonId(R.id.btn_gmail)
        .setEmailButtonId(R.id.btn_email)
        .build()

    return AuthUI.getInstance().createSignInIntentBuilder()
        .setIsSmartLockEnabled(!BuildConfig.DEBUG)
        .setAvailableProviders(
            listOf(
                AuthUI.IdpConfig.EmailBuilder().build(),
                AuthUI.IdpConfig.GoogleBuilder().build()
            )
        )
        .enableAnonymousUsersAutoUpgrade()
        .setLogo(R.mipmap.ic_launcher)
        .setAuthMethodPickerLayout(authUILayout)
        .build()
}

    java.lang.IllegalStateException: Launcher has not been initialized
at androidx.activity.compose.ActivityResultLauncherHolder.launch(ActivityResultRegistry.kt:153)
at androidx.activity.compose.ManagedActivityResultLauncher.launch(ActivityResultRegistry.kt:142)
at androidx.activity.result.ActivityResultLauncher.launch(ActivityResultLauncher.java:47)
at com.madhu.locationbuddy.profile.ProfileUIKt.ProfileUI(ProfileUI.kt:37)
at com.madhu.locationbuddy.profile.ProfileUIKt.ProfileUI(ProfileUI.kt:15)

Any ideas on how to resolve this issue?

like image 618
Babloo K Avatar asked Jan 25 '23 07:01

Babloo K


1 Answers

As per the Side-effects in Compose documentation:

Composables should be side-effect free.

Key Term: A side-effect is a change to the state of the app that happens outside the scope of a composable function.

Launching another activity, such as calling launch, is absolutely a side effect and therefore should never be done as part of the composition itself.

Instead, you should put your call to launch within one of the Effect APIs, such as SideEffect (if you want it to run on every composition) or LaunchedEffect (which only runs when the input changes - that would be appropriate if profileViewModel.isAnonymousUser was being driven by a mutableStateOf()).

Therefore your code could be changed to:

internal fun ProfileUI(profileViewModel: ProfileViewModel) {
    val loginLauncher = rememberLauncherForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { result ->
        if (result != null) {
         //do something
        }
    }
    if (profileViewModel.isAnonymousUser) {
        SideEffect {
            loginLauncher.launch(profileViewModel.buildLoginIntent())
        }
    } else {
        // Output your UI, etc.
    }
}
like image 171
ianhanniballake Avatar answered Feb 04 '23 04:02

ianhanniballake