For Result

En esta entrada vamos a explicar cómo se gestiona el retorno de información desde una actividad. Lo explicaremos con el código del ejercicio SaludoForResult.  Además veremos cómo detectar si la activida fue lanzada ForResult y cómo detectar la pulsación del botón Atrás del dispositivo.

Para la explicación utilizaremos el código del ejercicio SaludoForResult. Las pantallas de este ejemplo son las siguientes:

 

Como sabemos para lanzar una actividad se crea un intent y se utiliza el método StartActivity, pudiendo además añadir datos al intent que pueden ser recogidos por la actividad lanzada. Esto se ve en el siguiente codigo donde suponemos que lanzamos la Activity Saludo y enviamos información en un mapa con clave txtSaludo.

Intent intent = new Intent(this, Saludo.class);
intent.putExtra("txtSaludo", strSaludo);
startActivity(intent);

Para que podamos recibir información de la actividad Saludo deberemos lanzarla con StartActivityForResult. Este médoto además del intent, nos pide un código de solicitud o Request Code, para que a la vuelta de la información sepamos (mirando el request code que llegue) que se trata de esta solicitud.

En este ejercicio hemos utilizado un Switch para que el usuario elija, en la MainActivity, cómo lanzar la activity Saludo. El valor del switch se recoge como se hace con un check box, de la siguiente manera:

Boolean forResult = swForResult.isChecked();

En el siguiente fragmento de código vemos cómo en función del valor del switch lanzamos Saludo For Result o normal, además vemos que se comprueba que el valor del campo de texto de donde se coge la información para añadir al intent no sea vacío.

//Definido por ejemplo a nivel de clase MainAcitivity 
    static final int FOR_RESULT_REQUEST = 1; // The request code

...

if (!(strSaludo.isEmpty())) {
    Intent intent = new Intent(this, Saludo.class);
    intent.putExtra("txtSaludo", strSaludo);

    if (forResult) {
        startActivityForResult(intent,FOR_RESULT_REQUEST);
    }
    else {
        startActivity(intent);
    }
} else {
    Toast.makeText(getApplicationContext(), "Rellena el campo de texto", Toast.LENGTH_SHORT).show();
}

Si lanzamos For Result, entonces al retorno de la actividad Saludo, Android lanzará un método llamado onActivityResult que tendremos que implementar en nuestra actividad si queremos captuar el resultado. Este resultado vendrá en un intent y su información podrá ser obtenida de los Extra que lleve. Por ejemplo:

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

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

Este callback será puesto en funcionamiento independientemente de cual sea el requestCode que utilizamos cuando llamamos a StarActivityForResult. Vemos que el método recibe un requestCode, por el que podemos discriminar cómo fue llamada y por tanto qué datos recibimos. También recibe un resultCode que indica si se canceló o fue correcto el retorno, y por último un Intent  data con los datos.

Veamos ahora cómo en la actividad lanzada se gestiona el retorno y también cómo poder discriminar si fue lanzada For Result o no.

Esta sería la forma de determinar si una activity fue lanzada For Result o no, se hace uso del método getCallingActivity() de la Activity llamada, en nuestro caso Saludo, por lo que llamamos al método con Saludo.this.getCallingActivity :

ComponentName callingActivity = Saludo.this.getCallingActivity();
if (callingActivity != null) {
    //Activity was called For Result
}

En la actividad saludo podemos volver pulsando el botón Salir o con el botón Atrás del dispositivo.

Por defecto, cuando pulsamos el botón Atrás del dispositivo, Android destruye la actividad, por lo que la llamada a finish() la realiza “de oficio”. Sin embargo, cuando queremos cerrar la actividad y volver a la anterior en la pila de actividades, tendremos que llamar nosotros al método finish() para que termine. Esto lo vemos en el siguiente código:

btnSalir.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        ComponentName callingActivity = Saludo.this.getCallingActivity();
        if (callingActivity != null) {
            // Set the returning Intent
        }
        finish();
    }//onClick
}); //setOnClickListener

En este caso hemos utilizado un OnClickListener para el botón btnSalir al que hemos sobrecargado su médoto onClick() que es donde hemos comprobado si nos llamaron For Result o no. Como vemos al final del método OnClick() somos nosotros los que tenemos que llamar a finish() para terminar la activity.

Cuando pulsamos el botón Atras del dispositivo no tenemos que llamar a finish() porque Android lo hace por nosotros. Android pone en ejecución el callback onBackPressed(), que si lo sobrecargamos podremos capturar este evento, y en él queremos que en ese momento también se contsurya el Intent con la información de retorno si procede, y que después se proceda como por defecto. Para ello podemos utilizar el siguiente código que ya conocemos y llamando al final al código del objeto super para que se ejecute la acción por defecto.

@Override
public void onBackPressed(){
ComponentName callingActivity = Saludo.this.getCallingActivity();
if (callingActivity != null) {
    // Set the returning Intent
}
super.onBackPressed();
}

Como vemos tenemos pues dos sitios en donde construir el intent de retorno, por tanto creamos una función que será llamada en ambos casos, esta es:

private void SetActivityResult(){
    Toast.makeText(Saludo.this, "Retornando información", Toast.LENGTH_LONG).show();
    Intent returnIntent = new Intent();
    returnIntent.putExtra("txtResult",etName.getText().toString());
    setResult(Activity.RESULT_OK, returnIntent);
} //SetActivityResult