Fragments (fragmentos) en Android


Este artículo es tan profundo e ilustrativo que bien podríamos haber titulado como “Fragment vs Activity”, “Aplicaciones soportadas para varios tamaños de pantalla”, “Aprende a desarrollar en Android para APPs multi-dispositivo” o incluso “Fragments fácil o para Dummies". Antes de empezar he de decir que requiere conocimientos de Android avanzados. Previa a la descripción, te recomiendo que eches un vistazo a las Activitys en https://jarroba.com/activity-entender-y-usar-una-actividad/. Para los ejemplo usaremos listados, que detallamos en https://jarroba.com/listview-o-listado-en-android/, por lo que te recomiendo que le eches un vistazo si no lo has hecho ya. Empezaremos con unos conceptos mínimos pero breves, y programaremos nuestro primero programa funcional con Fragments en Android.

 

Me entusiasmo la frase que una vez dijera el filósofo Confucio (extraída de http://es.wikiquote.org/wiki/Confucio):

Cada cosa tiene su belleza, pero no todos pueden verla

Si la extrapolamos al terreno tecnológico en el que nos movemos, al de las pantallas táctiles; descubriremos que no es lo mismo un móvil, que una Tablet, que un reloj, que un monitor de unas pocas pulgadas, a una gran televisión, etc. Todas estas cosas tienen pantallas de muy diferente tamaño y cada uno es bello por lo que es. No podemos resistirnos al ver la belleza de los tamaños de las pantallas, pues no todos los usuarios deberán de ver lo mismo si usan objetos con tamaños de pantalla diferentes. Como desarrolladores tenemos que ver la belleza completa de cada cosa. Y tiene una razón de ser.

 

Como desarrollador de Android es muy común estar acostumbrados a programar las views aplicando dp para los tamaños, así las vistas se escalan para cada tipo de pantalla. Está bien para pantallas de pulgadas aproximadas a la que hemos desarrollado la aplicación en una primera instancia. Pero para nada está bien en pantallas de una gran diferencia de pulgadas. Como es diseñar una APP para un televisor de 100 pulgadas, y que también funcione en un reloj de 2 pulgadas; evidentemente se iba a ver diminuto e inmanejable. Lo mismo ocurre con la forma, no es lo mismo un Smartphone que tiende a ser rectangular bastante alargado, a un Tablet que suele respetar las proporciones áureas (misma forma que una tarjeta de crédito). Debemos hacernos siempre del mejor aprovechamiento del espacio de cada pantalla –tanto en tamaño como en forma- siempre en virtud de la comodidad del usuario.

Nota: Aquí solo nos interesa -además de la forma de la pantalla- el tamaño de pantalla, hablamos en pulgadas (normalmente la vemos representada como 7’’ o 7 pulgadas), a más pulgadas entonces pantalla más grande, a menos más pequeña. No nos interesa, y no confundir con el tamaño,  la resolución de la pantalla (que solemos ver cómo 1024×768). ¿Y porque no nos interesa? Porque la pantalla es a su vez interfaz táctil, por lo que define la comodidad de uso. Una pantalla más grande se verá más contenido que en más pequeña con el mismo esfuerzo; además, una pantalla más grande tiene más espacio para pulsar y manejar que una más pequeña. De ahí que la resolución carezca de importancia.

Para entenderlo vamos a suponer el siguiente ejemplo. Queremos un listado de animales. En cada fila de la lista mostrará el nombre del animal y una foto en miniatura.

Ejemplo Movil Listado Fragments Android - www.Jarroba.com

Al seleccionar un animal (una fila de la lista), me muestre el animal en detalle, es decir la descripción del animal.

Ejemplo Movil Detalle Fragments Android - www.Jarroba.com

Si te fijas en las imágenes anteriores, vemos el enunciado del ejemplo perfectamente reflejado en estas imágenes. Pero fíjate en una cosa más, ¿Qué dispositivo es el que ejecuta la aplicación? Un Smartphone, propiamente. Es decir, un dispositivo que cabe en la mano y que irá de las 3 a las 5 pulgadas más o menos; además, su forma suele ser rectangular alargada. Ahora bien, imagínate las mismas dos imágenes anteriores en un Tablet de unas 7 a 10 pulgadas aproximadamente. Si usáramos la aplicación directamente sobre un Tablet, te muestro como quedaría el listado:

Ejemplo Tablet Mal Fragments Android - www.Jarroba.com

Horrible ¿No crees que es una pérdida de espacio de la pantalla impresionante? Que la parte de la derecha pudiera dar lugar a mostrar otra cosa al usuario. Teniendo tanta pantalla se debe de aprovechar. Esto último se escusa en proporcionar una mejor experiencia al usuario con pantallas de tamaños diferentes, así como la de proporcionar acciones que de no disponer de cierto tamaño de pantalla no se podrían llevar a cabo, además de evitar la fragmentación de nuestro programa (seguro que te suena lo de la fragmentación de Android, pues en un programa Android se corrige con el uso de fragmentos, así nuestra aplicación será universal y usable para cualquier tamaño de pantalla).

Con el ejemplo, para una Tablet, se me ocurre que podríamos aprovechar el espacio derecho para mostrar el detalle. Así es mucho más cómodo y no hay que estar volviendo atrás cada vez.

Ejemplo Tablet Fragments Android - www.Jarroba.com

Mucho mejor. Al seleccionar un elemento del listado, se mostrará a la derecha el detalle del mismo. Mejor aprovechamiento de la pantalla y mucho más cómodo (no hay que volver atrás, se puede seleccionar otro inmediatamente).

Cabe aclarar que si mantenemos este diseño para un Smartphone, la comodidad del Tablet se pierde, pues no se podría leer bien la descripción del pájaro al aparecer muy pequeña y el listado sería difícil de pulsar al ser muy estrecho. Por esto tiene sentido que en el móvil tenga un diseño y funcionalidades diferentes al del Tablet.

Por cuestiones de espacio nos limitaremos al ejemplo de Smartphone y Tablet. Pero imagina que queremos hacer esta misma aplicación para un reloj de unas 2 pulgadas, puede que en vez de poner un listado pusiéramos un grid con las imágenes de los pájaros para que el dedo pudiera pulsar mejor los elementos, y la descripción aparecería aparte sin foto. O en una televisión de 40 pulgadas imagina la cantidad de cosas que entrarían; podríamos, por ejemplo, poner al lado de la descripción un vídeo del pájaro que vuela y debajo la ficha técnica, todo en la misma pantalla. Esto quiere decir que nos ajustamos al tamaño para realizar el diseño y la funcionalidad.

Por suerte para nosotros, no tenemos que hacer un diseño para cada pulgada de cada pantalla y para cada forma. Nos atendemos a la limitación por las modas. Pongo todos los dispositivos existentes con Android que pudiera ser bueno prestar atención al diseño y a la funcionalidad. Siempre claro, dependiendo del alcance de nuestra aplicación (las pulgadas y formas son orientativas):

  • Reloj (1 a 2 pulgadas, cuadrado)
  • Smarphone o dispositivo GPS (3 a 5 pulgadas, rectangular alargado)
  • Phablet (5 a 7 pulgadas, rectangular alargado)
  • Tablet (7 a 12 pulgadas, proporción aurea)
  • Pantalla de un ordenador (14 a 30 pulgadas, rectangular alargado o proporción aurea)
  • Televisión (30 a 80 pulgadas, proporción aurea)
  • Proyector (80 a 300 pulgadas, proporción aurea)

Dependerá del desarrollador saber a qué diseños y que funcionalidades atender en cada momento.

¿Y se puede hacer esto en la misma aplicación? o ¿Se desarrolla una App para cada tamaño de pantalla? La respuesta es, siempre desde la perspectiva del “buen programador”, se debe y se puede hacer en la misma aplicación. Los motivos son muy simples, que seguro estás harto de escuchar: modularidad y reusabilidad. Esto se logra con los Fragments o Fragmentos.

Si conoces el comportamiento de las Activities (ver en https://jarroba.com/activity-entender-y-usar-una-actividad/), advertirás que tienen un ciclo de vida y están asociadas a una vista (Layout en XML).

Un Fragment es un trozo (o un fragmento, si apelamos al mismo nombre que lo viste) de una actividad. Un Fragment tiene su propio Layout y su propio ciclo de vida.

Puedes apreciar, que programándolo una vez, puedes rehusar el código para que se adapte a diferentes tamaños de pantalla con la disposición de los elementos que quieras.

Por lo que adivinarás que un Fragment siempre ha de estar en una Activity, no puede existir independiente. Y el ciclo de vida de la Activity contenedora afectará al del Fragment; por ejemplo, si se pausa la Activity el o los Fragments, que estén en esta actividad, serán pausados.

Hablando del ciclo de vida de un Fragment, no podemos continuar sin dedicarle la parte que se merece. Es el siguiente, y no te asustes de lo largo que es, si entendiste el de Activity este es parecido (Gráficos extraídos de http://developer.android.com/guide/components/fragments.html, modificados y traducidos por www.Jarroba.com):

Ciclo de vida de un fragmento o Fragment de Android - www.Jarroba.com

Para que conozcas a grandes rasgos que es lo que hace cada una de los métodos, te los detallo en la siguiente imagen (Referencia en http://developer.android.com/reference/android/app/Fragment.html):

Ciclo de vida explicado de un fragmento o Fragment de Android - www.Jarroba.com

Nota: Como ya hicieramos con Activity en este otro artículo, dejo un ejemplo simple -sirve como plantilla o snippet- de un Fragment, con todos sus métodos (decir tiene que no todos son obligatorios; pero el constructor vacío sí que lo es, lo explico en el siguiente artículo) y el log puesto para ver por donde va entrando:

public class Fragment_de_ejemplo extends Fragment {

	private final String LOG_TAG = "test";

	public Fragment_de_ejemplo() {
	}

	@Override
	public void onAttach (Activity activity) {
		super.onAttach(activity);
		Log.v(LOG_TAG, "onAttach");
	}

	@Override
	public void onCreate (Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		Log.v(LOG_TAG, "onCreate");
	}

	@Override
	public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
		View rootView = inflater.inflate(R.layout.miLayout, container, false);
		Log.v(LOG_TAG, "onCreateView");
		/* Aquí podemos seleccionar las Views contenidas en el Layout para trabajar con ellas, por ejemplo con:
		 * TipoView miView = (TipoView) rootView.findViewById(R.id.miViewXML);
		 */
		return rootView;
	}

	@Override
	public void onActivityCreated (Bundle savedInstanceState) {
		super.onActivityCreated(savedInstanceState);
		Log.v(LOG_TAG, "onActivityCreated");
	}

	@Override
	public void onViewStateRestored (Bundle savedInstanceState) {
		super.onViewStateRestored(savedInstanceState);
		Log.v(LOG_TAG, "onViewStateRestored");
	}

	@Override
	public void onStart () {
		super.onStart();
		Log.v(LOG_TAG, "onStart");
	}

	@Override
	public void onResume () {
		super.onResume();
		Log.v(LOG_TAG, "onResume");
	}

	@Override
	public void onPause () {
		super.onPause();
		Log.v(LOG_TAG, "onPause");
	}

	@Override
	public void onStop () {
		super.onStop();
		Log.v(LOG_TAG, "onStop");
	}

	@Override
	public void onDestroyView () {
		super.onDestroyView();
		Log.v(LOG_TAG, "onDestroyView");
	}

	@Override
	public void onDestroy () {
		super.onDestroy();
		Log.v(LOG_TAG, "onDestroy");
	}

	@Override
	public void onDetach () {
		super.onDetach();
		Log.v(LOG_TAG, "onDetach");
	}

}

 

Hemos creído conveniente dividir este artículo en dos partes por comodidad y optimización. Este primero más teórico, y una segunda parte que dispone de un ejemplo completo de como programar con Fragments para Android completamente explicado: en la siguiente página, a la que puedes ir pinchando aquí mismo.

 

Comparte esta entrada en:
Safe Creative #1401310112503
Fragments (fragmentos) en Android por "www.jarroba.com" esta bajo una licencia Creative Commons
Reconocimiento-NoComercial-CompartirIgual 3.0 Unported License.
Creado a partir de la obra en www.jarroba.com

14 comentarios en “Fragments (fragmentos) en Android”

  1. Hola, buen tutorial gracias por el tiempo.

    Tengo una consulta, en el evento "onCreateView" el layout se asocia al fragment, pero…¿qué layout?

    Saludos. Espero tu respuesta.

    1. Los Fragments cambian ligeramente respecto a los Activities, pero son muy sencillos. Para asociarlo al Layour en el mismo onCreateView puede llamar a:

      View rootView = inflater.inflate(R.layout.miLayout, container, false);

      Donde rootView lo devuelves en el return del método onCreateView.

    1. Para añadir un SearchView tienes un ejemplo en http://developer.android.com/guide/topics/search/search-dialog.html

  2. Hola buenas noches, llevo toda la tarde con el ejemplo de los fragments, me ha salido de la primera , vengo del vba y he trabajado con C# pero hace 5 años asi que estoy muy oxidado con las classes, tengo un problema, la aplicacion que estoy creando tiene una actividad principal, que desde unos buttons llamo a las demas actividades y todo muy bien , los frames muy buenos para lo que quiero realizar, pero me instala 2 iconos iguales la app , en uno abre la aplicacion perfecta y voy a todas las actividades y el otro icono , me abre los fragmes solamente, hay estoy perdido y no doy con el error.

    un cordial saludo kinito y gracias por estas estupendas explicaciones

    1. Prueba a desinstalar la aplicación desde el desinstalador y comprueba que no haya otra segunda con otra firma diferente; si es así desinstálala también y vuelve a probar

      1. Hola Ramón, gracias por responder tan rápido, he desinstalado todo varias veces, hasta he cambiado el proyecto de carpeta y sigo con los dos iconos , debe haber algo en el código que se me escapa, como todavía estoy en pruebas y aprendiendo , creare un nuevo proyecto y are lo mismo a ver si lo arreglo.

        Un cordial saludo kinito

        1. Sin ver el código es complicado decirte mucho. Solo se me ocurre que tengas algo mal en el AndroidManifest.xml, revisalo.

          1. Hola Ramon, acertadamente el error estaba en Manifest, problema en los nodos , ya esta solucionado , muchas gracias por tu interes.

            Un cordial saludo kinito

  3. Buenas tardes.

    Estoy realizando una aplicación con fragments en la que mediante un FragmentLayout en la misma ventana. El problema que tengo es que cargo el fragment1, a continuación cargo el fragment2 y el fragment1 desaparece. Pero lo que sucede es que los botones que tenia el fragment 1 se pueden pulsar desde el fragment2 aunque el fragment1 uno no se vea. Es como si el fragment dos fuera transparente aunque si que tiene background y su propia vista.

    Esto solo me sucede cuando la transacción la hago con add() y no con replace(). No entiendo a que se debe esto.

    Un saludo.

     

     

    1. Buenas Adrian, asegurate de que has sustituido correctamente el Fragment (tienes ejemplos de como hacerlo en http://jarroba.com/libro-android-100-gratis/)

  4. Excelente explicación teórica y gracias por compartir estos temas, pasamos ahora a la segunda parte del tutorial y como lo mencione, está muy bien explicada y detallada la parte teórica de este artículo de Fragments.

    ¡Muchas gracias!

  5. Hola Ramón, he leído casi todos vuestros posts y me parecen muy trabajados y divulgativos. Gracias.
    Tengo una consulta relacionada con los fragments. Estoy acabando una aplicación en la que la pantalla más importante contiene datos de coordenadas, captación de un código, grabación y reproducción de audios, toma de fotos y visualización con una gallery, videos, medidas de sensores, etc. Dado que el número de líneas se acercaba a las diez mil, opté por usar fragments para intentar sacar código de la activity y hacerlo mas mantenible. No todos los fragments se ven a la vez, sino que lo visualizo en función de que actuemos sobre una pestaña (que realmente son botones simulados). Todos los fragments los cargo al cargar la activity y solo trabajo ocultando o no el layout correspondiente en función de la pestaña seleccionada.
    Quisiera tu opinión sobre este uso de los fragments que, lo cierto, es que no me acaba de convencer aunque en un primer momento me pareció lo mas pertinente.
    Un saludo y gracias. Carlos

    1. Buenas Carlos,

      Haces muy bien al dividir código en Fragments para hacer el código más mantenible, ya que los Fragments se pueden emplear tanto visibles como sólo de lógica.

      Te recomiendo que uses pestañas de navegación (mira un ejemplo en http://developer.android.com/guide/topics/ui/actionbar.html#NavigationStyles). Así no tendrás que cargar todos los Fragments a la vez, únicamente utilizarás los necesarios cada momento y se descargarán cuando no se necesiten (si cargas todos de golpe, en un dispositivo con poca potencia lo más seguro que tendrás problemas de memoria).

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Uso de cookies

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies

ACEPTAR
Aviso de cookies