En android, si necesitamos pasar datos entre nuestras actividades, tendremos que indicar a nuestro Intent que datos desemos pasar. Para ello, disponemos de los métodos putExtra(String name, String value). En el parámetro name le indicaremos el nombre que deseamos dar al valor que vamos a pasar, con el formato del prefijo del paquete.
Para ver un ejemplo, vamos a crear un programa que va a representar un pedido, mediante una clase de cabecera y una lista de clases de líneas. Vamos a pasar de nuestra primera actividad a la segunda el id de un pedido, la dirección a la que se tiene que enviar y el número de líneas que tiene.
Intent intent = new Intent(this, SegundaPantallaActivity.class); intent.putExtra("com.jtristan.parcelable.ID_PEDIDO", pedido.getId()); intent.putExtra("com.jtristan.parcelable.DIRECCION", pedido.getDireccion()); intent.putExtra("com.jtristan.parcelable.NUMERO_LINEAS", pedido.getLineas().size()); startActivity(intent);
En la actividad “SegundaPantallaActivity” recuperamos los valores creándonos un objeto de la clase Bundle. Esta clase nos provee un método get para cada tipo de dato que podemos recuperar.
Bundle extra = this.getIntent().getExtras(); pedido.setId(extra.getLong("com.jtristan.parcelable.ID_PEDIDO")); pedido.setDireccion(extra.getString("com.jtristan.parcelable.DIRECCION")); int numero_lineas_pedido = extra.getInt("com.jtristan.parcelable.NUMERO_LINEAS");
Como podemos observar en la documentación de Intent, estamos trabajando sólo con tipos primitivos y arrays de los mismos. ¿Qué pasa si necesitamos pasar un objeto?. ¿No podemos pasar nuestros objetos pedidos?. Podríamos serializar nuestras clases implementando la interfaz java.io.Serializable. Sin embargo, la serialización en android supone un gran problema de rendimiento. Por ello, android dispone de la interfaz Parcelable. Es una interfaz específica para “serializar” nuestros objetos y poder pasarlos entre las actividades, optimizando el rendimiento.
Vamos a ver como podemos implementar la interfaz Parcelable para poder pasar un pedido junto con sus líneas entre dos actividades. Para que el ejemplo sea más completo, vamos a poder almacenas tanto una lista de pedidos como un único pedido en la cabecera del pedido.
private Long id; private String nombre; private String direccion; private boolean servido; private LineaPedido linea; private ArrayList lineas; public CabeceraPedido(){ linea = new LineaPedido(); lineas = new ArrayList(); } //Omitimos los get y los set public CabeceraPedido(Parcel parcel){ this(); readToParcel(parcel); } public static final Parcelable.Creator CREATE = new Parcelable.Creator() { public CabeceraPedido createFromParcel(Parcel parcel) { return new CabeceraPedido(parcel); } public CabeceraPedido[] newArray(int size) { return new CabeceraPedido[size]; } };
En primer lugar nos creamos un constructor para la “serialización de la clase”. Vamos a llamar a este constructor cuando queramos recuperar los valores. Como podéis ver, en el constructor llamamos al constructor CabeceraPedido() para instanciar la Lista y el objeto Pedido.
Cuando implementamos la interfaz Parcelable, necesitamos declararnos una variable estática de tipo Parcelable.Creator que se llamará CREATOR y que va a ser la encargada de implementar la interfaz Parcelable.Creator. Esta interfaz tiene dos métodos, mediante los cuales vamos a poder devolver los valores que previamente hemos almacenado.
Para almacenar los datos tenemos que implementar el método writeToParcel(Parcel dest, int flags). La clase Parcel nos provee métodos específicos para cada uno de los valores que vamos a poder almacenar.
public void writeToParcel(Parcel parcel, int flags) { parcel.writeLong(id); parcel.writeString(nombre); parcel.writeString(direccion); parcel.writeString(String.valueOf(servido)); parcel.writeTypedList(lineas); parcel.writeParcelable(linea, flags); }
Para poder “serializar” la lista de pedidos utilizaremos el método writeTypedList (List val)
Para ello, tenemos que hacer que la clase LineaPedido implemente también Parcelable.
Si quisiesemos pasar simplemente un objeto Línea, utilizaremos writeParcelable(Parcelable p, int parcelableFlags).
Para leer los datos, disponemos de los métodos read.
public void readToParcel(Parcel parcel){ String servido; id = parcel.readLong(); nombre = parcel.readString(); direccion = parcel.readString(); servido = parcel.readString(); if (servido.equals("true")) this.servido = true; else this.servido = false; parcel.readTypedList(lineas, LineaPedido.CREATOR); linea = parcel.readParcelable(LineaPedido.class.getClassLoader()); }
Como habréis podido observar no disponemos de un método específico para los booleanos. Cuando vayamos a recuperar los datos tendremos que aplicar nosotros la conversión.
Es fundamental, que leamos los datos en el mismo orden en que les hemos escrito.
Finalmente, en nuestra clase Activity, una vez declarado el intent pasaremos el objeto con putExtra(String name, Parcelable value). Funciona igual que cuando vamos a pasar un tipo primitivo como hemos visto al comienzo del artículo.
Intent intent = new Intent(this, SegundaPantalla.class); intent.putExtra("com.jtristan.parcelable.PEDIDO", pedido); startActivity(intent);
Al cargar la segunda actividad recuperamos los valores mediante un objeto Bundle.
public class SegundaPantallaActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); CabeceraPedido pedido = new CabeceraPedido(); LineaPedido linea = new LineaPedido(); ArrayList lineas = new ArrayList(); Bundle extra = this.getIntent().getExtras(); pedido.setId(extra.getLong("com.jtristan.parcelable.ID_PEDIDO")); pedido.setDireccion(extra.getString("com.jtristan.parcelable.DIRECCION")); int numero_lineas_pedido = extra.getInt("com.jtristan.parcelable.NUMERO_LINEAS"); Log.i("PEDIDO", pedido.getId().toString() + " " + pedido.getDireccion() + " " + String.valueOf(numero_lineas_pedido)); pedido = extra.getParcelable("com.jtristan.parcelable.PEDIDO"); Log.i("PEDIDO", pedido.getId().toString() + " " + pedido.getNombre() + " " + pedido.getDireccion() + " " + pedido.isServido()); lineas = pedido.getLineas(); for (int i=0; i<lineas.size();i++){ linea = lineas.get(i); Log.i("LINEA", linea.getId().toString() + " " + linea.getMaterial() + " " + linea.getCantidad().toString() + " " + linea.getPrecio().toString()); } } }