¿Cómo gestionar startActivityForResult en Android?

969

En mi actividad, llamo a una segunda actividad de la actividad principal por startActivityForResult. En mi segunda actividad, hay algunos métodos que terminan esta actividad (tal vez sin un resultado), sin embargo, solo uno de ellos devuelve un resultado.

Por ejemplo, desde la actividad principal, llamo una segunda. En esta actividad, verifico algunas características del teléfono, como si tiene una cámara. Si no es así, cerraré esta actividad. Además, durante la preparación MediaRecordero MediaPlayersi ocurre un problema, cerraré esta actividad.

Si su dispositivo tiene una cámara y la grabación se realiza por completo, luego de grabar un video si un usuario hace clic en el botón Listo, enviaré el resultado (dirección del video grabado) a la actividad principal.

¿Cómo verifico el resultado de la actividad principal?

Hesam
fuente

Respuestas:

2447

Desde su FirstActivityllamada, el método de SecondActivityuso startActivityForResult()

Por ejemplo:

int LAUNCH_SECOND_ACTIVITY = 1
Intent i = new Intent(this, SecondActivity.class);
startActivityForResult(i, LAUNCH_SECOND_ACTIVITY);

En su SecondActivityconjunto, los datos a los que desea volver FirstActivity. Si no desea regresar, no configure ninguno.

Por ejemplo: en SecondActivitysi desea devolver datos:

Intent returnIntent = new Intent();
returnIntent.putExtra("result",result);
setResult(Activity.RESULT_OK,returnIntent);
finish();

Si no desea devolver datos:

Intent returnIntent = new Intent();
setResult(Activity.RESULT_CANCELED, returnIntent);
finish();

Ahora en su FirstActivityclase escriba el siguiente código para el onActivityResult()método.

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == LAUNCH_SECOND_ACTIVITY) {
        if(resultCode == Activity.RESULT_OK){
            String result=data.getStringExtra("result");
        }
        if (resultCode == Activity.RESULT_CANCELED) {
            //Write your code if there's no result
        }
    }
}//onActivityResult

Para implementar el paso de datos entre dos actividades de una manera mucho mejor en Kotlin, vaya a este enlace ' Una mejor manera de pasar datos entre actividades '

Nishant
fuente
1
¿Cuál es el propósito de poner una intención cuando RESUT_CANCELLED en setResult (RESULT_CANCELED, returnIntent);
Ismail Sahin
44
@ismail Suponga que SecondActivity, en el caso de que ocurriera alguna excepción, en ese caso también debe devolver el resultado al FirstActivity, para que pueda establecer el resultado como "RESULT_CANCELLED"en el bloque catch y volver FirstActivtyy en el FirstActivity's' 'onActivityResult()que puede verificar si obtuvo el resultado de éxito o fracaso.
Nishant
10
Depende de usted, si no necesita saber el motivo de la cancelación, puede usar simplemente setResult (RESULT_CANCELED); sin ninguna intención
Ismail Sahin
2
@Lei Leyba No se llama a finish () después de llamar a startActivityForResult (). First Actvity se moverá al estado de pausa.
Nishant
66
Para mí no funciona -.- esto es lo que odio tanto de Android - este sistema es tan poco confiable: - /
Martin Pfeffer
50

¿Cómo verificar el resultado de la actividad principal?

Debe anular y Activity.onActivityResult()luego verificar sus parámetros:

  • requestCodeidentifica qué aplicación devolvió estos resultados. Esto lo define usted cuando llama startActivityForResult().
  • resultCode le informa si esta aplicación tuvo éxito, falló o algo diferente
  • datacontiene cualquier información devuelta por esta aplicación. Esto puede ser null.
Sam
fuente
¿Significa que requestCode solo se usa en la primera actividad y nunca se usa para la segunda actividad? Si la segunda actividad tiene diferentes enfoques, cambiaría, pero se basaría en la intención adicional y no en el código de solicitud, ¿verdad? Editar: Sí, stackoverflow.com/questions/5104269/…
JCarlosR
44

Complementando la respuesta de @ Nishant, la mejor manera de devolver el resultado de la actividad es:

Intent returnIntent = getIntent();
returnIntent.putExtra("result",result);
setResult(RESULT_OK,returnIntent);
finish();

Estaba teniendo problemas con

new Intent();

Luego descubrí que la forma correcta es usar

getIntent();

para obtener la intención actual

Julián Alberto
fuente
Se siente un poco extraño crear un nuevo Intentque solo existe para contener Bundleay no tiene los valores normales como una acción o componente. Pero también se siente un poco extraño (¿y potencialmente peligroso?) Modificar lo Intentque se usó para iniciar la actividad actual. Así que busqué en la fuente el propio Android y descubrí que siempre crean uno nuevo Intentpara usar como resultado. Por ejemplo, github.com/aosp-mirror/platform_frameworks_base/blob/…
spaaarky21
Hola spaaarky21, gracias por tu comentario. Lamento no haber sido tan claro al explicar exactamente cómo terminé con esa solución. Fue hace tres años, y solo puedo recordar que mi aplicación se estaba bloqueando debido a "nueva intención", a eso me refería cuando dije "estaba teniendo problemas". En realidad solo intenté con "getIntent", porque tenía sentido en ese momento, ¡y funcionó! Por eso decidí compartir mi solución. Quizás no sea la mejor elección de palabras para decir "la mejor manera" o "la forma correcta", pero defiendo mi solución. Es lo que resolvió mi problema y, aparentemente, de otras personas también. Gracias
Julian Alberto
1
¡Guauu! Funciona genial. getIntent()parece ser una manera perfecta de devolver datos a una actividad desconocida, desde donde se ha llamado la actividad. ¡Gracias!
Sam
43

Ejemplo

Para ver todo el proceso en contexto, aquí hay una respuesta complementaria. Vea mi respuesta más completa para más explicaciones.

ingrese la descripción de la imagen aquí

MainActivity.java

public class MainActivity extends AppCompatActivity {

    // Add a different request code for every activity you are starting from here
    private static final int SECOND_ACTIVITY_REQUEST_CODE = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    // "Go to Second Activity" button click
    public void onButtonClick(View view) {

        // Start the SecondActivity
        Intent intent = new Intent(this, SecondActivity.class);
        startActivityForResult(intent, SECOND_ACTIVITY_REQUEST_CODE);
    }

    // This method is called when the second activity finishes
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        // check that it is the SecondActivity with an OK result
        if (requestCode == SECOND_ACTIVITY_REQUEST_CODE) {
            if (resultCode == RESULT_OK) { // Activity.RESULT_OK

                // get String data from Intent
                String returnString = data.getStringExtra("keyName");

                // set text view with string
                TextView textView = (TextView) findViewById(R.id.textView);
                textView.setText(returnString);
            }
        }
    }
}

SecondActivity.java

public class SecondActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
    }

    // "Send text back" button click
    public void onButtonClick(View view) {

        // get the text from the EditText
        EditText editText = (EditText) findViewById(R.id.editText);
        String stringToPassBack = editText.getText().toString();

        // put the String to pass back into an Intent and close this activity
        Intent intent = new Intent();
        intent.putExtra("keyName", stringToPassBack);
        setResult(RESULT_OK, intent);
        finish();
    }
}
Suragch
fuente
¿Pueden hacerlo dos aplicaciones diferentes A y la aplicación b? stackoverflow.com/questions/52975645/…
Jerry Abraham
12

Para aquellos que tienen problemas con requestCode incorrecto en onActivityResult

Si llama startActivityForResult()desde su Fragment, la Actividad que posee el Fragmento cambia el código de solicitud.

Si desea obtener el código de resultado correcto en su actividad, intente esto:

Cambio:

startActivityForResult(intent, 1); A:

getActivity().startActivityForResult(intent, 1);

Tomasz Mularczyk
fuente
10

Si desea actualizar la interfaz de usuario con el resultado de la actividad, no puede usar this.runOnUiThread(new Runnable() {} Al hacer esto, la IU no se actualizará con un nuevo valor. En cambio, puedes hacer esto:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (resultCode == RESULT_CANCELED) {
        return;
    }

    global_lat = data.getDoubleExtra("LATITUDE", 0);
    global_lng = data.getDoubleExtra("LONGITUDE", 0);
    new_latlng = true;
}

@Override
protected void onResume() {
    super.onResume();

    if(new_latlng)
    {
        PhysicalTagProperties.this.setLocation(global_lat, global_lng);
        new_latlng=false;
    }
}

Esto parece una tontería pero funciona bastante bien.

DaviF
fuente
2

En primer lugar se utiliza startActivityForResult()con los parámetros en primera Activityy si desea enviar datos desde la segunda Activitya la primera Activityy luego pasa valor utilizando Intentcon setResult()método y obtener que los datos dentro de onActivityResult()método en el primero Activity.

Dharmendra Pratap
fuente
1

Problema muy común en Android
Se puede dividir en 3 Piezas
1) iniciar la Actividad B (sucede en la actividad A)
2) Establecer los datos solicitados (sucede en la actividad B)
3) Recibir los datos solicitados (sucede en la actividad A)

1) startActivity B

Intent i = new Intent(A.this, B.class);
startActivity(i);

2) Establecer datos solicitados

En esta parte, usted decide si desea devolver los datos o no cuando ocurre un evento en particular.
Por ejemplo: en la actividad B hay un EditText y dos botones b1, b2.
Al hacer clic en el Botón b1, los datos vuelven a la actividad A
Al hacer clic en el Botón b2 no se envían datos.

Enviando datos

b1......clickListener
{
   Intent resultIntent = new Intent();
   resultIntent.putExtra("Your_key","Your_value");
   setResult(RES_CODE_A,resultIntent);
   finish();
}

No enviando datos

b2......clickListener
    {
       setResult(RES_CODE_B,new Intent());
       finish();
    }

el usuario hace clic en el botón Atrás
De manera predeterminada, el resultado se establece con el código de respuesta Activity.RESULT_CANCEL

3) Recuperar resultado

Para eso anular el método onActivityResult

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);

if (resultCode == RES_CODE_A) {

     // b1 was clicked 
   String x = data.getStringExtra("RES_CODE_A");

}
else if(resultCode == RES_CODE_B){

   // b2 was clicked

}
else{
   // back button clicked 
}
}
Rohit Singh
fuente
1

ActivityResultRegistry es el enfoque recomendado

ComponentActivityAhora proporciona una ActivityResultRegistryque le permite manejar el startActivityForResult()+ onActivityResult(), así como requestPermissions()+ onRequestPermissionsResult()fluye sin anulando métodos en su Activityo Fragment, aporta una mayor seguridad a través de tipo ActivityResultContract, y proporciona enlaces para probar estos flujos.

Se recomienda encarecidamente utilizar las API de resultados de actividad introducidas en AndroidX Activity 1.2.0-alpha02 y Fragment 1.3.0-alpha02.

Agregue esto a su build.gradle

def activity_version = "1.2.0-alpha03"

// Java language implementation
implementation "androidx.activity:activity:$activity_version"
// Kotlin
implementation "androidx.activity:activity-ktx:$activity_version"

¿Cómo usar el contrato preconstruido?

Esta nueva API tiene las siguientes funcionalidades preconstruidas

  1. Toma video
  2. PickContact
  3. Obtener el contenido
  4. GetContents
  5. OpenDocument
  6. OpenDocuments
  7. OpenDocumentTree
  8. CreateDocument
  9. Marcar
  10. Tomar la foto
  11. Solicitar permiso
  12. RequestPermissions

Un ejemplo que utiliza takePicture contract:

private val takePicture = prepareCall(ActivityResultContracts.TakePicture()) 
     { bitmap: Bitmap? ->
        // Do something with the Bitmap, if present
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        button.setOnClickListener { takePicture() }
       }

Entonces, ¿qué está pasando aquí? Vamos a desglosarlo un poco. takePicturees solo una devolución de llamada que devuelve un mapa de bits anulable: si es nulo o no depende de si el onActivityResultproceso fue exitoso o no . prepareCallluego registra esta llamada en una nueva función ComponentActivityllamada ActivityResultRegistry- volveremos a esto más adelante. ActivityResultContracts.TakePicture()es uno de los ayudantes integrados que Google ha creado para nosotros, y finalmente invocandotakePicture realidad activa la intención de la misma manera que lo haría anteriormente Activity.startActivityForResult(intent, REQUEST_CODE).

¿Cómo escribir un contrato personalizado?

Contrato simple que toma un Int como Entrada y devuelve una Cadena que la Actividad solicitada devuelve en la Intención del resultado.

    class MyContract : ActivityResultContract<Int, String>() {

    companion object {
        const val ACTION = "com.myapp.action.MY_ACTION"
        const val INPUT_INT = "input_int"
        const val OUTPUT_STRING = "output_string"
    }

    override fun createIntent(input: Int): Intent {
        return Intent(ACTION)
            .apply { putExtra(INPUT_INT, input) }
    }

    override fun parseResult(resultCode: Int, intent: Intent?): String? {
        return when (resultCode) {
            Activity.RESULT_OK -> intent?.getStringExtra(OUTPUT_STRING)
            else -> null
        }
    }
}



    class MyActivity : AppCompatActivity() {

    private val myActionCall = prepareCall(MyContract()) { result ->
        Log.i("MyActivity", "Obtained result: $result")
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...
        button.setOnClickListener {
            myActionCall(500)
        }
    }
}

Consulte esta documentación oficial para más información.

Darish
fuente
0
You need to override Activity.onActivityResult()

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);

if (resultCode == RESULT_CODE_ONE) {


   String a = data.getStringExtra("RESULT_CODE_ONE");

}
else if(resultCode == RESULT_CODE_TWO){

   // b was clicked

}
else{

}
}
Nitesh Dev Kunwar
fuente