Buenos días, hoy vamos a ver como implementar la interface Parcelable en nuestros proyectos Android.
Esta interface es usada por Android principalmente, para poder pasar objetos de una clase entre nuestras Activities, agregandolas al Intent
Esta interface es fácil de implementarlas y vamos a crear una clase con diferentes miembros de diferentes tipos para ver como se puede hacer.
Creación de una clase que implemente la interface
Lo primero que haremos es crear una clase nueva, en mi caso la llamaré Model e implementará la interface Parcelable.
public class Model implements Parcelable {
private long unLong;
private double unDouble;
private float unFloat;
private String unString;
private boolean unBoolean;
private OtraClase unParcelable;
// Setters y getters
}
He agregado los tipos de datos mas comunes que se me han presentado en varios proyectos, por lo que tenemos un long, un double, un float, un String, un boolean y OtraClase que es una clase que a su vez también implementa la interface Parcelable.
Sustituir los métodos que necesitamos
Para implementar la interface Parcelable tendremos que implementar una serie de métodos que vamos a necesitar como veremos a continuación
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
}
Además, deberemos implementar un campo static llamado CREATOR como vemos a continuación:
public static final Parcelable.Creator<Model> CREATOR = new Parcelable.Creator<Model>() {
@Override
public Model createFromParcel(Parcel source) {
return null;
}
@Override
public Model[] newArray(int size) {
return new null;
}
};
Estos son los métodos o campos que deberemos agregar, y en el siguiente paso les aplicaremos lo necesario para que sea funcional.
Adaptar la implementación
Ahora vamos a ver como podemos adaptar estos métodos y campos a nuestra clase:
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(unLong);
dest.writeDouble(unDouble);
dest.writeFloat(unFloat);
dest.writeString(unString);
dest.writeByte((byte) (unBoolean == true ? 1 : 0));
dest.writeParcelable(unParcelable, flags);
}
public static final Parcelable.Creator<Model> CREATOR = new Parcelable.Creator<Model>() {
@Override
public Model createFromParcel(Parcel source) {
return new Model(source);
}
@Override
public Model[] newArray(int size) {
return new Model[size];
}
};
private Model(Parcel source) {
this.unLong = source.readLong();
this.unDouble = source.readDouble();
this.unFloat = source.readFloat();
this.unString = source.readString();
this.unBoolean = source.readByte() == 1 ? true : false;
this.unParcelable = source.readParcelable(OtraClase.class
.getClassLoader());
}
Vamos a ir parte por parte para comprender bien lo que está pasando:
Aquí vemos como «escribimos» en un objeto de la clase Parcel los elementos de nuestra clase.
CREATOR
Código:
public static final Parcelable.Creator<Model> CREATOR = new Parcelable.Creator<Model>() {
@Override
public Model createFromParcel(Parcel source) {
return new Model(source);
}
@Override
public Model[] newArray(int size) {
return new Model[size];
}
};
Aquí vemos como implementamos el campo static que es necesario para implementar correctamente la interface. Lo que hacemos es sustituir los métodos createFromParcel que nos servirá para reconstruir nuestro objeto en base a un objeto de la clase Parcel. Para ello deberemos suministrar un constructor que reciba un argumento de la clase Parcel.
Cabe destacar, y es muy importante, debemos leerlos en el mismo orden en el cual los escribimos, ya que tiene un enfoque FIFO (first input first output).
OtraClase
Nuestra otra clase que implementa esta interface es mas simple y podemos ver su código a continuación:
public class OtraClase implements Parcelable {
private long id;
// Setter y getter
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(id);
}
private OtraClase(Parcel source) {
this.id = source.readLong();
}
public static final Parcelable.Creator<OtraClase> CREATOR = new Parcelable.Creator<OtraClase>() {
@Override
public OtraClase createFromParcel(Parcel source) {
return new OtraClase(source);
}
@Override
public OtraClase[] newArray(int size) {
return new OtraClase[size];
}
};
}
Probarlo en el emulador
Ahora probamos todo esto en una Activity simple, el cual vemos a continuación su código:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Instanciamos nuestra Clase
final Model model = new Model();
// Asignamos Valores
model.setUnLong(10);
model.setUnDouble(10.0d);
model.setUnFloat(20.0f);
model.setUnString("Parcelable");
model.setUnBoolean(true);
final OtraClase otra = new OtraClase();
otra.setId(1000);
model.setUnParcelable(otra);
// Imprimimos su resultado en la consola
Model.printModel(model);
// Lanzamos la siguiente Activity donde comprobaremos los valores de nuevo
launchSecondActivity(model);
}
private void launchSecondActivity(Model model){
Intent intent = new Intent(this, SecondActivity.class);
intent.putExtra("PARCELABLE", model);
startActivity(intent);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
El código es bastante simple, solo creamos una instancia de nuestra clase, imprimimos el resultado y luego vamos a otra Activity que simplemente recibirá el objeto y lo imprimirá en el log.
public class SecondActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
// Obtenemos nuestro Parcelable desde el Intent
final Model model = getIntent().getParcelableExtra("PARCELABLE");
// Imprimimos sus valores
Model.printModel(model);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.second, menu);
return true;
}
}
Como vemos, recibimos el objeto e imprimimos los valores, pudiendo ver en el LogCat lo siguiente:
12-22 19:30:48.149: I/unLong(2199): El id es 10
12-22 19:30:48.149: I/unDouble(2199): El double es 10.0
12-22 19:30:48.157: I/unFloat(2199): El float es 20.0
12-22 19:30:48.157: I/unString(2199): El String es Parcelable
12-22 19:30:48.157: I/unBoolean(2199): El boolean es true
12-22 19:30:48.157: I/unParcelable(2199): El id de OtraClase es 1000
12-22 19:30:48.157: I/ActivityManager(482): START u0 {cmp=sekth.droid.parcelabletutorial/.SecondActivity (has extras)} from pid 2199
12-22 19:30:48.261: I/unLong(2199): El id es 10
12-22 19:30:48.261: I/unDouble(2199): El double es 10.0
12-22 19:30:48.261: I/unFloat(2199): El float es 20.0
12-22 19:30:48.261: I/unString(2199): El String es Parcelable
12-22 19:30:48.261: I/unBoolean(2199): El boolean es true
12-22 19:30:48.261: I/unParcelable(2199): El id de OtraClase es 1000
Esto es todo sobre una implementación básica de la interface Parcelable, pero en algunos casos se requerirá algo mas complejo y habrá que hacer alguna cosa mas especial.
El código de este ejemplo podemos encontrarlo disponible en GitHub
Sin más, cualquier aporte o corrección es bienvenido.
Buenas tardes, debido a que he recibido varios comentarios o peticiones sobre crear aplicaciones con Fragment y la funcionalidad de Maestro-Detalle, me he decidido a subir esta entrada.
La funcionalidad Maestro-Detalle es importante cuando vamos a desarrollar aplicaciones para dispositivos que son Tablet, ya que gracias a los Fragment podemos tener varios paneles a la vez en la pantalla. En el caso de que nuestra apiicación tenga como uso final solo los SmartPhone, esta funcionalidad no es mala idea, pero no le sacaríamos todo el potencial, ya que la diferencia entre tamaños de pantalla es bastante grande (aunque cada vez menos). En el caso de que nuestra aplicación tenga como finalidad cubrir los SmartPhone y las Tablets, es buena idea implementar este tipo de funcionalidad, ya que podemos controlar cuando el dispositivo es Tablet o SmartPhone, y así con una sola aplicación cubrir ambos dispositivos. Ahora mismo parece una locura, pero lo veremos a lo largo de la entrada.
Con esta pequeña introducción nos ponemos manos a la obra:
Creación del Proyecto
Para comenzar vamos a crear un proyecto de aplicación Android. Para ello nos dirigiremos a File->New->Android Application Project. Si no encontramos esta opción vamos a Other, y en la lista que nos aparece buscamos la opción deseada. También podemos introducir «Android» en el campo de texto para filtrar los resultados y que sea mas rápido.
Una vez aceptemos el tipo de proyecto, nos aparecerá el asistente de Android, en el cual a través de unos simples pasos tendremos nuestro proyecto creado. En la primera ventana se nos da a elegir el nombre de nuestra aplicación, al igual que el nombre del proyecto. En mi caso lo he llamado «EjemploMaestroDetalle» aunque el nombre es lo de menos y podéis asignarle el que querais. El resto podeis dejarlo como querais o cambiar el rango de versiones de Android que vais a cubrir según vuestras necesidades.
A medida que avancemos nos aparecerá la opción de crear nuestra primera Activity y su layout, en mi caso he dejado el nombre como está, MainActivity y su layout como activity_main.
Una vez terminemos el asistente, tendremos nuestro proyecto listo y creado para seguir construyendo nuestra aplicación.
TituloFragment
Antes de meternos con la Activity vamos a crear lo necesario para montar todo en la Activity. Para esta funcionalidad vamos a necesitar 2 Fragment, uno será un ListFragment que contendrá una lista de lo que sea, y otro Fragment que contendrá el contenido adecuado del elemento pulsado en el ListFragment.
En este punto vamos a desarrollar la funcionalidad e importancia que tendrá este ListFragment. Vamos a ver su código, que luego explicaremos paso a paso:
public class TituloFragment extends ListFragment {
onTituloSelectedListener mCallback;
// Interface que la Activity contenedora debe implementar
// para poder tener comunicación
public interface onTituloSelectedListener {
public void onTituloSelected(int position);
}
@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
// Establecemos el Adapter cuando se crea el Fragment
setListAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, Contenido.titulos));
}
@Override
public void onAttach(Activity activity) {
// TODO Auto-generated method stub
super.onAttach(activity);
// Inicializamos nuestra variable de referencia del tipo
// onTituloSelectedListener junto con el valor del objeto
// activity que debe ser una Activity que implemente esta interface
try {
mCallback = (onTituloSelectedListener) activity;
} catch (ClassCastException e) {
Log.d("ClassCastException",
"La Activity debe implementar esta Interface");
}
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
// TODO Auto-generated method stub
super.onListItemClick(l, v, position, id);
// Llamamos al método que implementa la Activity pasandole
// la posicion del elemento que hemos pulsado
mCallback.onTituloSelected(position);
}
}
Como podemos observar en grandes rasgos, vemos que tiene una interface, carga un array en la lista y poco más. Vamos a analizar los elementos:
onTituloSelectedListener
Esta interface es la que vamos a usar para comunicar este ListFragment con el otro Fragment, y esto se hará a través de la FragmentActivity o Activity.
public interface onTituloSelectedListener {
public void onTituloSelected(int position);
}
onCreate
En este método, perteneciente al ciclo de vida del Fragment vamos a establecer el ArrayAdapter en la lista, para cargar una serie de elementos.
@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
// Establecemos el Adapter cuando se crea el Fragment
setListAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, Contenido.titulos));
}
onAttach
En este método, también perteneciente al ciclo de vida de los Fragment vamos a poder instanciar la variable de instancia que hemos definido, que es del tipo onTituloSelectedListener, exactamente, la interface que hemos creado. Esto lo hacemos para que pueda haber comunicación entre nuestra Activity y este Fragment. En el caso de que la Activity no implemente la interface recibiremos una excepción del tipo ClassCastException.
@Override
public void onAttach(Activity activity) {
// TODO Auto-generated method stub
super.onAttach(activity);
// Inicializamos nuestra variable de referencia del tipo
// onTituloSelectedListener junto con el valor del objeto
// activity que debe ser una Activity que implemente esta interface
try {
mCallback = (onTituloSelectedListener) activity;
} catch (ClassCastException e) {
Log.d("ClassCastException",
"La Activity debe implementar esta Interface");
}
}
onListItemClick
Este método viene con la clase ListFragment y nos debe de ser ya conocido de los ListView. Lo único que hará es llamar al método que la Activity implementa, pasandole la posición del elemento que hemos pulsado, y en la Activity se redirige el resto.
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
// TODO Auto-generated method stub
super.onListItemClick(l, v, position, id);
// Llamamos al método que implementa la Activity pasandole
// la posicion del elemento que hemos pulsado
mCallback.onTituloSelected(position);
}
ContenidoFragment
Esta es la clase del otro Fragment que vamos a usar y será el encargado de mostrar el contenido para un elemento que pulsemos en el ListFragment. En este Fragment debemos implementar algún método más, ya que recibirá una posición y tendremos que tratar con ella para mostrar el contenido.
Vamos a ver su código para luego comentar cada método que necesitemamos implementar:
public class ContenidoFragment extends Fragment {
public static final String POSICION = "position";
int position = -1;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
// Comprobamos si se recupera de un estado anterior
if (savedInstanceState != null) {
position = savedInstanceState.getInt("position");
}
return inflater.inflate(R.layout.contenido_fragment, container, false);
}
@Override
public void onStart() {
// TODO Auto-generated method stub
super.onStart();
// Comprobamos si tenemos argumentos
Bundle args = getArguments();
if (args != null) {
// Si tenemos argumentos, establecemos la posicion
actualizarContenido(args.getInt(POSICION));
} else if (position != -1) {
// Si la variable de instancia es diferente a -1
// quiere decir que nos hemos recuperado de un estado anterior
// y actualizamos el contenido
actualizarContenido(position);
}
}
public void actualizarContenido(int position) {
// Instanciamos el TextView y establecemos el contenido
TextView tvContenido = (TextView) getActivity().findViewById(
R.id.tvContenido);
tvContenido.setText(Contenido.descripcion[position]);
// Guardamos la posicion del elemento que estamos consultando
this.position = position;
}
@Override
public void onSaveInstanceState(Bundle outState) {
// TODO Auto-generated method stub
super.onSaveInstanceState(outState);
// Guardamos el estado de la posicion del elemento
// que estábamos consultando
outState.putInt(POSICION, position);
}
}
Analicemos todo por partes:
onCreateView
Este método pertenece al ciclo de vida de los Fragment. en él vamos a crear el View del Fragment, que será «inflado» por el objeto de la clase LayoutInflater haciendo uso de un layout muy simple, el cuál únicamente contiene un TextView.
Observamos también que tratamos el objeto savedInstanceState para comprobar si el Fragment se está recuperando de un estado anterior. Con esto controlaremos que si por algún caso hemos cambiado orientación de la pantalla o algo, al recrearse el Fragment volvamos a tener disponible el contenido que estábamos usando, y no ninguno en su lugar.
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
// Comprobamos si se recupera de un estado anterior
if (savedInstanceState != null) {
position = savedInstanceState.getInt("position");
}
return inflater.inflate(R.layout.contenido_fragment, container, false);
}
actualizarContenido
Este método debemos crearlo y será el encargado de recibir un entero con un valor, el cual trataremos. Instanciaremos el TextView del layout, para tener acceso a el y a continuación estableceremos su contenido en base al entero que hemos recibido.
public void actualizarContenido(int position) {
// Instanciamos el TextView y establecemos el contenido
TextView tvContenido = (TextView) getActivity().findViewById(
R.id.tvContenido);
tvContenido.setText(Contenido.descripcion[position]);
// Guardamos la posicion del elemento que estamos consultando
this.position = position;
}
onStart
Este método también pertenece al ciclo de vida de los Fragment y lo usaremos para llamar al método actualizarContenido. Este método se ejecuta cuando el Fragment ya ha sido creado, y se ha empezado a ejecutar. Comprobamos si tiene algún argumento mediante el uso de la clase Bundle. Si este objeto no es null vamos a extraer el dato guardado y lo vamos a mandar al método actualizarContenido el cual tratará con el entero que hemos extraído. En el caso de que nuestra variable de instancia tenga un valor de -1, vamos a actualizar el contenido con el valor de nuestra variable de instancia, lo que quiere decir que el Fragment se ha recuperado de un estado anterior.
@Override
public void onStart() {
// TODO Auto-generated method stub
super.onStart();
// Comprobamos si tenemos argumentos
Bundle args = getArguments();
if (args != null) {
// Si tenemos argumentos, establecemos la posicion
actualizarContenido(args.getInt(POSICION));
} else if (position != -1) {
// Si la variable de instancia es diferente a -1
// quiere decir que nos hemos recuperado de un estado anterior
// y actualizamos el contenido
actualizarContenido(position);
}
}
onSaveInstanceState
Este método lo vamos a usar para guardar el estado del Fragment, ya que así podremos restaurarlo y volver a la aplicación justo por donde lo dejamos.
@Override
public void onSaveInstanceState(Bundle outState) {
// TODO Auto-generated method stub
super.onSaveInstanceState(outState);
// Guardamos el estado de la posicion del elemento
// que estábamos consultando
outState.putInt(POSICION, position);
}
MainActivity
Ahora sí vamos a implementar lo necesario para que nuestra aplicación funcione tanto en dispositivos SmartPhones como Tablets adaptando el diseño de la UI.
Para comenzar vamos a ver que debemos crear 2 archivos xml para su layout. Uno vendrá ya creado y vamos a ver su contenido a continuación:
Como vemos tenemos un elemento FrameLayout el cuál será el contenedor del Fragment. Este layout será el que usará Android en caso de que el dispositivo sea SmartPhone.
Ahora vamos a ir a la carpeta res/, donde crearemos otra carpeta dentro de ella, llamado layout-large. En esta carpeta vamos a crear un nuevo archivo layout, con el mismo nombre que el anterior, «activity_main.xml». Este layuot contendrá lo siguiente:
vemos que al contrario que el anterior, vamos a tener un LinearLayout con orientación horizontal y almacenará 2 Fragment. Esto es así ya que en el caso de ejecutar la aplicación en una Tablet, directamente se usará este layout y tendremos nuestra funcionalidad Maestro-Detalle.
Bien, ya tenemos los layouts, pero ahora tenemos que manejar como usarlos junto a nuestros Fragments y los distintos tipos de pantalla, vamos a ello.
En el código de nuestra Activity tendremos lo siguiente:
public class MainActivity extends FragmentActivity implements
TituloFragment.onTituloSelectedListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Comprobamos si estamos usando la version con
// con el FrameLayout
if (findViewById(R.id.fragment_container) != null) {
if (savedInstanceState != null) {
return;
}
// Establecemos el ListFragment en el caso de que sea la version
// de un panel (SmartPhone)
TituloFragment fragment = new TituloFragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, fragment, null).commit();
}
}
@Override
public void onTituloSelected(int position) {
// TODO Auto-generated method stub
// Comprobamos si tenemos disponible el Fragment de
// contenido
ContenidoFragment contFragment = (ContenidoFragment) getSupportFragmentManager()
.findFragmentById(R.id.contenidoFragment);
if (contFragment != null) {
// Si está disponible, estamos en la versión de 2 paneles
contFragment.actualizarContenido(position);
} else {
// Si no está disponible, estamos en el layout
// del FrameLayout, y tenemos que cambiar los Fragment
contFragment = new ContenidoFragment();
Bundle args = new Bundle();
// Establecemos la posición que hemos elegido
args.putInt(ContenidoFragment.POSICION, position);
contFragment.setArguments(args);
// Reemplazamos el Fragment que había por el nuevo
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, contFragment)
.addToBackStack(null).commit();
}
}
}
Vamos a analizar todo parte por parte:
onCreate
Este método pertenece al ciclo de vida de una Activity y es el primero en ejecutarse.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Comprobamos si estamos usando la version con
// con el FrameLayout
if (findViewById(R.id.fragment_container) != null) {
if (savedInstanceState != null) {
return;
}
// Establecemos el ListFragment en el caso de que sea la version
// de un panel (SmartPhone)
TituloFragment fragment = new TituloFragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, fragment, null).commit();
}
}
Lo primero que hacemos es comprobar si existe un View llamado «fragment_container». Esta View corresponde al FrameLayout de nuestro activity_main en la carpeta res/layout. Cuando ejecutamos la aplicación en un SmartPhone se comprobará el layout que se ha elegido, si estamos usando este layout, y la View con id «fragment_container» está disponible, quiere decir que estamos usando la versión en la que solo mostramos un Fragment a la vez, por tanto establecemos el ListFragment que hemos denominado TituloFragment.
En el caso de que se ejecutara en una tablet, el resultado de la comprobación con el método findViewById sería null, y por tanto los Fragment ya estarían colocados, como hemos hecho en el layout para Tablets.
onTituloSelected
Este método tenemos que implementarlo cuando nuestra Activity implementa la interface de nuestro TituloFragment. Aquí trataremos también si se está ejecutando la versión SmartPhone, en el cual deberemos reemplazar el Fragment que ya existe por el otro, o la versión de Tablet, en el cuál le mandaremos un extra con la posición.
@Override
public void onTituloSelected(int position) {
// TODO Auto-generated method stub
// Comprobamos si tenemos disponible el Fragment de
// contenido
ContenidoFragment contFragment = (ContenidoFragment) getSupportFragmentManager()
.findFragmentById(R.id.contenidoFragment);
if (contFragment != null) {
// Si está disponible, estamos en la versión de 2 paneles
contFragment.actualizarContenido(position);
} else {
// Si no está disponible, estamos en el layout
// del FrameLayout, y tenemos que cambiar los Fragment
contFragment = new ContenidoFragment();
Bundle args = new Bundle();
// Establecemos la posición que hemos elegido
args.putInt(ContenidoFragment.POSICION, position);
contFragment.setArguments(args);
// Reemplazamos el Fragment que había por el nuevo
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, contFragment)
.addToBackStack(null).commit();
}
}
Lo primero que hacemos es comprobar si tenemos disponible un ContenidoFragment disponible. En el caso de que esté disponible quiere decir que estamos usando la versión de 2 paneles (Tablet), por tanto lo único que haremos es llamar a su método actualizarContenido pasandole un entero, que es la posición que hemos recibido como argumento.
En caso contrario, estamos en la versión de 1 panel únicamente a la vez (SmartPhone) por lo que deberemos reemplazar el Fragment que ya existe por otro. Lo que haremos es instanciar el Fragment, crear un objeto de la clase Bundle para pasarle la posición y agregarselo. A continuación hacemos uso del método getSupportFragmentManager() para comenzar una transacción en la que reemplazaremos el contenido que ya existe por el nuevo Fragment. Luego hacemos uso del método addToBackStack() para poder volver al Fragment anterior y completamos el cambio con el método commit().
Con esto tendríamos ya nuestra aplicación funcionando tanto en Tablets como en SmartPhones con un comportamiento diferente debido a sus tipos de pantalla.
Vemos a continuación una serie de capturas de pantalla y un vídeo en el que vemos la diferencia entre ambos dispositivos.
Unos vídeos de los diferentes emuladores ejecutando la misma aplicación:
Ejemplo en Tablet:
Ejemplo en SmartPhone:
Con esta entrada hemos visto como adaptar nuestras aplicaciones tanto a dispositivos Tablet como SmartPhone por medio del uso de Fragment. Al principio puede ser algo complejo pero todo es tener claro lo que queremos hacer para hacerlo sin dudas y sin tener que cambiar la mitad de la aplicación mas adelante.
Este ejemplo es muy parecido al que se encuentra en la página web de Android Developer, el cuál es el siguiente: http://developer.android.com/training/basics/fragments/communicating.html . Comov eremos es prácticamente igual, ya que llegado a cierto punto todo termina pareciendose cuando tienen la misma funcionalidad.
El código usado en el ejemplo podéis descargarlo de aquí y está disponible también en GitHub: aquí
Sin más, cualquier aporte o corrección es bienvenido.