¿Cómo reemplazar startActivityForResult con las API de resultados de actividad?

6 minutos de lectura

avatar de usuario
Neoh

Tengo una actividad principal que sirve como punto de entrada para llamar a diferentes actividades, dependiendo de la condición. Entre otros, uso Firebase Auth para administrar el inicio de sesión de los usuarios:

startActivityForResult(
            AuthUI.getInstance().createSignInIntentBuilder()
                    .setAvailableProviders(providers)
                    .build(),
            RC_SIGN_IN)

sobrescribo onActivityResult() para distinguir la intención/datos devueltos, por ejemplo:

 override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    when (requestCode) {

        REQUEST_CODE_1 -> {
          // update UI and stuff
        }

        RC_SIGN_IN -> {
          // check Firebase log in
        }
        // ...
    }
}

Con las API de resultados de actividad, que recomienda enfáticamente el documentaciónentiendo que debo hacer prepareCall() antes de ActivityResultLauncher y para asegurarme de que la actividad esté en estado creado cuando la inicie, pero todavía no entiendo cómo manejar los resultados de múltiples actividades con gracia (al menos, en un solo lugar) como en onActivityResult().

Mirando a Este artículoparece que necesito implementar múltiple niño clases internas de ActivityResultContract tipo (por lo tanto múltiples prepareCall()‘s?), porque se supone que son diferentes contratos, ¿Estoy en lo correcto? ¿Puede alguien mostrarme algún ejemplo de esqueleto que refleje lo anterior? onActivityResult() ¿lógica?

avatar de usuario
Misha Akopov

Puede llamar a tantas actividades para obtener el resultado que desee y tener una devolución de llamada separada para cada una:

    val startForResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult())
    { result: ActivityResult ->
        if (result.resultCode == Activity.RESULT_OK) {
            //  you will get result here in result.data
            }

        }
    }

    startForResult.launch(Intent(activity, CameraCaptureActivity::class.java))

Solo necesita especificar la clase de actividad: CameraCaptureActivity::class.java

Actualizar:

The prepareCall() method has been renamed to registerForActivityResult() in Activity 1.2.0-alpha04 and Fragment 1.3.0-alpha04. And it should be startForResult.launch(...) in the last line

Gracias rafael tavares para actualizar

  • los prepareCall() el método ha sido renombrado a registerForActivityResult() en Actividad 1.2.0-alpha04 y Fragmento 1.3.0-alpha04. y debería ser startForResult.launch(...) en la última línea

    –Rafael Tavares

    10 de septiembre de 2020 a las 11:23


  • ¿Qué hay de pasar? 'android.content.Intent intent, int requestCode' como parámetros?

    – ÁtomoX

    10 de abril de 2021 a las 12:58


  • Pero, para devolver el resultado de la Actividad2, ¿es lo mismo de siempre?: setResult(Bundle)???

    – mantc_sdr

    10 de junio de 2021 a las 9:19

  • devuelve result.data como nulo

    – Karunesh Palekar

    4 de agosto de 2021 a las 12:39

avatar de usuario
Hardik Hirpara

Desde ahora, startActivityForResult() ha quedado en desuso, así que use un nuevo método en lugar de eso.

Ejemplo

public void openActivityForResult() {
    
 //Instead of startActivityForResult use this one
        Intent intent = new Intent(this,OtherActivity.class);
        someActivityResultLauncher.launch(intent);
    }


//Instead of onActivityResult() method use this one

    ActivityResultLauncher<Intent> someActivityResultLauncher = registerForActivityResult(
            new ActivityResultContracts.StartActivityForResult(),
            new ActivityResultCallback<ActivityResult>() {
                @Override
                public void onActivityResult(ActivityResult result) {
                    if (result.getResultCode() == Activity.RESULT_OK) {
                        // Here, no request code
                        Intent data = result.getData();
                        doSomeOperations();
                    }
                }
            });

  • Pruebe este código con el inicio de sesión de Google enActivityForResult sin suerte, ¿alguna sugerencia?

    – Tipo

    16 de mayo de 2021 a las 1:35

  • este código funcionó para mí; aunque tuve que traducir a kotlin. Gracias

    – federico verchez

    28 de mayo de 2021 a las 1:04

  • Gracias por no usar “var” y lambdas 🙂

    – paulsm4

    13 de agosto de 2021 a las 3:32

  • Más simplificado y claramente descrito ✓

    – basaveshwar lamtura

    28 de diciembre de 2021 a las 18:58

  • Puedo confirmar que funcionó perfectamente

    – Ezequiel Adrián

    29 de enero a las 17:48

Primero, no olvide agregar esto a su dependencia de Gradle

implementation 'androidx.activity:activity-ktx:1.2.0-alpha05'
implementation 'androidx.fragment:fragment-ktx:1.3.0-alpha05'

En segundo lugar, cree su contrato de resultado extendiendo una clase abstracta llamada ActivityResultContract<I, O>. Me refiero al tipo de entrada y O significa el tipo de salida. Y luego solo necesita anular 2 métodos

class PostActivityContract : ActivityResultContract<Int, String?>() {

    override fun createIntent(context: Context, input: Int): Intent {
        return Intent(context, PostActivity::class.java).apply {
            putExtra(PostActivity.ID, postId)
        }
    }

    override fun parseResult(resultCode: Int, intent: Intent?): String? {
        val data = intent?.getStringExtra(PostActivity.TITLE)
        return if (resultCode == Activity.RESULT_OK && data != null) data
        else null
    }
}

Y finalmente, el último paso es registrar el contrato para Activity. Debe pasar su contrato personalizado y devolución de llamada a registerForActivityResult.

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
      
        start_activity_contract.setOnClickListener {
            openPostActivityCustom.launch(1)
        }
    }
  
    // Custom activity result contract
    private val openPostActivityCustom =
        registerForActivityResult(PostActivityContract()) { result ->
            // parseResult will return this as string?                                              
            if (result != null) toast("Result : $result")
            else toast("No Result")
        }
}

Para más información marque esto Correo

  • Estaba buscando las dependencias, gracias por agregar esto. Consigue un voto a favor 🙂

    – Despertar Neo

    21 de junio de 2021 a las 15:29

  • Es bueno saber que te ayudó 🙂

    – Krisna Sony

    22 de junio de 2021 a las 17:19

  • Un buen enfoque para especificar la solicitud Intent! ¡Gracias!

    – YUSMLE

    28 de noviembre de 2021 a las 13:09


En este caso, lo que AuthUI devolvió ya era un Intent, por lo que lo usamos como en el ejemplo a continuación.

private val startForResult =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
            when(result.resultCode){
                RESULT_OK -> {
                    val intent = result.data
                    // Handle the Intent...
                    mUser = FirebaseAuth.getInstance().currentUser
                }
                RESULT_CANCELED -> {

                } else -> {
            } }
        }

inicie la actividad desde cualquier lugar (por ejemplo, al hacer clic en un botón) usando:

 AuthUI.getInstance().createSignInIntentBuilder().setAvailableProviders(providers)
            .build().apply {
                startForResult.launch(this)
            }

List<AuthUI.IdpConfig> providers = Arrays.asList(
                    new AuthUI.IdpConfig.EmailBuilder().build(),
                    new AuthUI.IdpConfig.GoogleBuilder().build());

            ActivityResultLauncher<Intent> launcher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
                if (result.getResultCode() == Activity.RESULT_OK) {
                    Log.v("LOGIN OK", "OK Result for Login");
                }
            });
            
            launcher.launch(AuthUI.getInstance()
                    .createSignInIntentBuilder()
                    .setIsSmartLockEnabled(false)
                    .setAvailableProviders(providers)
                    .build());

Ver esto para más detalles:
https://githubmemory.com/repo/firebase/FirebaseUI-Android/issues?cursor=Y3Vyc29yOnYyOpK5MjAyMS0wMy0wNVQyMjoxNzozMyswODowMM4xEAQZ&pagination=next&page=2

avatar de usuario
Arvind Sharma

Use esto para Firebase AuthUI;

final ActivityResultLauncher<Intent> launcher = registerForActivityResult(
            new FirebaseAuthUIActivityResultContract(), this::onSignInResult);

    binding.loginSignup.setOnClickListener(view -> {
        List<AuthUI.IdpConfig> provider = Arrays.asList(new AuthUI.IdpConfig.EmailBuilder().build(),
                new AuthUI.IdpConfig.GoogleBuilder().build(),
                new AuthUI.IdpConfig.PhoneBuilder().build());
        Intent intent = AuthUI.getInstance()
                .createSignInIntentBuilder()
                .setIsSmartLockEnabled(false)
                .setAlwaysShowSignInMethodScreen(true)
                .setAvailableProviders(provider)
                .build();
        launcher.launch(intent);
    });


private void onSignInResult(FirebaseAuthUIAuthenticationResult result) {

    if (result.getResultCode() == RESULT_OK) {
        FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
        if (user != null) {
            if (user.getMetadata() != null) {
                if (user.getMetadata().getCreationTimestamp() != user.getMetadata().getLastSignInTimestamp()) {
                    Toast.makeText(this, "Welcome Back", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(this, "Welcome", Toast.LENGTH_SHORT).show();
                }
                startMainActivity();
            }
        }
    } else {
        IdpResponse response = result.getIdpResponse();
        if (response == null)
            Toast.makeText(this, "Canceled By You", Toast.LENGTH_SHORT).show();
        else Log.d(TAG, "onCreate: ActivityResult" + response.getError());
    }
}

private void startMainActivity() {
    Intent intent = new Intent(LoginActivity.this, MainActivity.class);
    startActivity(intent);
    finish();
}

Como esto.

avatar de usuario
CoolMind

Si inicia una actividad desde un fragmento y devuelve el resultado al fragmento, haga esto.

En fragmento:

private lateinit var activityResult: ActivityResultLauncher<Intent>

activityResult = registerForActivityResult(
    ActivityResultContracts.StartActivityForResult()) { result ->
    if (result.resultCode == RESULT_OK) {
        val data = result.data
        doSomeOperations(data)
    }
}

SomeActivity.showScreen(activityResult, requireContext())

En actividad:

// activity?.setResult(Activity.RESULT_OK) doesn't change.

companion object {

    fun showScreen(activityResult: ActivityResultLauncher<Intent>, context: Context) {
        val intent = Intent(context, SomeActivity::class.java)
        activityResult.launch(intent)
    }
}

  • ¿Qué es SomeActivity.showScreen(activityResult, requireContext()) quiero decir, ¿qué es showScreen? ¿Puedes describir más?

    – Yogui Arif Widodo

    1 de febrero a las 22:24

  • @YogiArifWidodo, fun showScreen(activityResult: ActivityResultLauncher<Intent>, context: Context) en la 2da parte de la respuesta. Puedes abrir una actividad SomeActivity de un fragmento, realice algunas acciones y devuelva un resultado de esa actividad al fragmento.

    – CoolMind

    2 de febrero a las 7:15

¿Ha sido útil esta solución?