domingo, 19 de octubre de 2014

Uso de Intents

Un Intent se emplea habitualmente para lanzar una Activity, ya sea de la propia aplicación o de una aplicación externa.

Compatibilidad

v1

Lo mínimo necesario

Para lanzar una Activity de la propia app se usa un Intent explícito, ya que el nombre de la clase que representa la Activity destino es conocido:
  • Disponer de todas las activities configuradas en el Manifest:
<activity
android:name="es.hubiqus.drawer.NoticiasActivity"
android:label="@string/app_name"
android:configChanges="orientation|screenSize" >
</activity>

  • Lanzar la segunda Activity desde código:
startActivity(new Intent(getActivity(), NoticiaActivity.class));

Un Intent implícito define una llamada al sistema operativo. En este caso lo que se define es una acción general a ejecutar  y la información para el Activity destino, de forma que el sistema es quien decide qué app o componente del mismo debe ejecutar para satisfacer la orden.
Por ejemplo, empleo de un Intent para ver una web, que la visualizará en un navegador del dispositivo:
//Acción ver
//La URL debe ser de servidor externo en formato correcto http(s)://...
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);

Además de la información básica, en la llamada del Intent se pueden incluir otros elementos extra, como se puede ver en el siguiente código para compartir información con otras apps:
//Acción enviar
Intent intent = new Intent(Intent.ACTION_SEND);

//Tipo de contenido que se va a enviar
intent.setType("text/plain");
//Asunto
intent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.app_name));
//Texto
intent.putExtra(Intent.EXTRA_TEXT, shareText);
//Crear diálogo para seleccionar app
startActivity(Intent.createChooser(intent, getString(R.string.compartir)));

También es posible incluir flags que determinan cómo atenderá el sistema operativo a la petición:
Intent intent = new Intent(getActivity(), InicioActivity.class);
//Limpiar todo el back stack
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);

Parámetros

Para pasar parámetros a un Intent se puede emplear un Bundle:
Bundle args = new Bundle();
args.putSerializable(NoticiaActivity.PARAM_ITEM, noticia);

Intent intent = new Intent(getActivity(), NoticiaActivity.class);
intent.putExtras(args);
startActivity(intent);

También se puede emplear un paso directo de parámetros básicos a través de las distintas versiones del método putExtra de la clase Intent, sin necesidad de usar el Bundle.
Los datos se recogen en la Activity destino a través de getIntent:
Bundle args = getIntent().getExtras();

Serializable y Parcelable

Además de datos de tipos básicos Java, en Android se pueden emplear para comunicar activities o fragments dos tipos especiales de clases. Cualquier clase que implemente el interfaz Serializable o Parcelable se convierte automáticamente en una clase que puede ser pasada a través de parámetro de forma sencilla.
Serializable es el interfaz Java clásico para serializar (convertir una clase en representación de bytes) y poder enviar de un extremo a otro. En Android se introduce Parcelable como una alternativa más eficiente.
Implementar un interfaz Serializable es muy sencillo, simplemente se necesita añadir la cabecera correspondiente a la clase siempre que dicha clase se encuentre formada por atributos que a su vez sean serializables, tales como tipos básicos o clases habituales (String, ArrayList, …). En caso de disponer de atributos no serializables será necesario implementar los métodos del interfaz para indicar cómo se realizan las conversiones de información.
public class Noticia implements Serializable {

En el caso de Parcelable, aunque se trate de una conversión de tipos básicos sí que es imprescindible implementar algunos métodos y disponer de una clase Creator. El comportamiento es análogo al que se emplea para serializar y deserializar un objeto, escribir los datos hacia el Parcel en un orden y recogerlos en el mismo orden.
public class Persona implements Parcelable {
      
       private String nombre;
       private String direccion;
      
       /**
        * Constructor usado para recrear un objeto desde un parcel
        * @param in parcel del cual leer el objeto
        */
       public Poi(Parcel in) {
             this.nombre = in.readString();
             this.direccion = in.readString();
       }

      
@Override
       public int describeContents() {
             return 0;
       }

@Override
       public void writeToParcel(Parcel dest, int flags) {
             dest.writeString(nombre);
             dest.writeString(direccion);
       }

       public static final Parcelable.Creator<Persona> CREATOR =
new Parcelable.Creator<Persona>() {
             public Persona createFromParcel(Parcel in) {
                    return new Persona(in);
             }

             public Persona[] newArray(int size) {
                    return new Persona[size];
             }
       };

}

Resultados

Cuando un Intent lanza una Activity habitualmente cede el control a la misma y no espera un retorno. En Android también es posible comunicar las activities para producir un resultado desde la segunda Activity que sea empleado en la primera.
En primer lugar es necesario lanzar el Intent empleando el método startActivityForResult acompañado de una constante que será definida en la clase y que simplemente actúa como etiqueta para saber qué Activity fue lanzada:
//Acción para selección de imagen
private static final int SEL_IMAGEN = 0;
//Acción para selección de localización
private static final int SEL_COORDENADA = 1;
...

startActivityForResult(intent, SEL_IMAGEN);

El método onActivityResult será quien se encargue de recoger el resultado y actuar en consecuencia. Este método es invocado automáticamente al recuperar la Activity llamante el control del sistema, es decir, cuando la segunda Activity se cierra y en pantalla vuelve a aparecer la anterior.
@Override
public void onActivityResult(int reqCode, int resultCode, Intent intent) {
       //reqCode es la constante que determina qué Activity fue invocada
switch (reqCode) {
       case SEL_IMAGEN:
//resultCode OK indica que se produjo resultado en el destino
              if (resultCode == Activity.RESULT_OK) {
       ...
             }
             break;
       case SEL_COORDENADA:
              if (resultCode == Activity.RESULT_OK) {
...
             }
             break;      
       }
}

En la Activity destino se guarda el resultado en un Intent el cual se pasará a la Activity principal a través del parámetro correspondiente del método onActivityResult.
Bundle args = new Bundle();
args.putString(PARAM_RES, "Resultado de la Activity 2");
            
Intent result = new Intent();
result.putExtras(args);

setResult(Activity.RESULT_OK, result);

Referencias

http://developer.android.com/reference/android/os/Parcelable.html

No hay comentarios:

Publicar un comentario