Fragments: ListFragment en Android

Buenas tardes, en esta entrada vamos a ver algo más sobre los Fragments en Android, en este caso es un tipo de Fragment creado para una tarea específica, en este caso para mostrar un ListView, como si de una ListActivity se tratase.


Para esta entrada, se requiere un poco de conocimiento sobre los Fragment, para que se usan y cual es su objetivo en el desarrollo de aplicaciones para Android.

  • Introducción a Fragments: aquí.
  • Fragment Dinámicos: aquí.

Con esta pequeña introducción, podemos ponernos manos a la obra para construir nuestra aplicación basada en ListFragment:

  • Creación del Proyecto Android

    Para crear nuestro nuevo proyecto, nos vamos a dirigir a File -> New -> Android Application Project. En el caso de que no dispongamos de él en la lista, nos dirigiremos a “Other”, y a continuación lo buscaremos en la lista que nos aparecerá, o si queremos podemos introducir “Android” en la caja de texto, filtrandose así todos aquellos campos que sean de Android.

    Una vez nos aparezca la primera ventana del asistente, vamos a darle un nombre a nuestro proyecto, en mi caso lo he llamado EjemploListFragment, aunque podeis darle el que vosotros querais. El resto de las opciones podeis dejarlas igual.

    Cuando aparezca la ventana del asistente en el cuál nos dé la posibilidad de darle un nombre a nuestra Activiy, vamos a llamarla EjemploListFragment, o el nombre que querais, y su archivo layout se llamará activity_ejemplo_list_fragment.xml.

    Cuando terminemos el asistente, podremos seguir con la creación de nuestra aplicación.

  • EjemploListFragment

    Una vez hemos creado nuestro proyecto, vamos a tener nuestra Activity principal creada, junto a su archivo layout, el cual vamos a editar y que se encuentra bajo la carpeta res/layout/activity_ejemplo_list_fragment.xml:

    		<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    		    xmlns:tools="http://schemas.android.com/tools"
    		    android:layout_width="match_parent"
    		    android:layout_height="match_parent"
    		    android:orientation="horizontal"
    		    tools:context=".EjemploListFragment" >
    		
    		    <fragment
    		        android:id="@+id/fragment1"
    		        android:name="sekth.droid.Fragment.Fragment1"
    		        android:layout_width="0dp"
    		        android:layout_height="wrap_content"
    		        android:layout_weight="0.5" />
    		
    		    <fragment
    		        android:id="@+id/fragment2"
    		        android:name="sekth.droid.Fragment.Fragment1"
    		        android:layout_width="0dp"
    		        android:layout_height="wrap_content"
    		        android:layout_weight="0.5" />
    		
    		</LinearLayout>
    		

    Como vemos, vamos a meter 2 Fragment, que al fin y al cabo es el mismo pero 2 veces, para que podamos ver que se pueden meter tantos como queramos (En la medida de lo posible, claro, y según las necesidades que se dén), ya que son como pequeñas actividades con sus propios ciclos de vida.

    El código java de nuestra Activity principal, EjemploListFragment.java localizado bajo la carpeta src/nombre_del_paquete/EjemploListFragment.java contiene lo siguiente:

    		package sekth.droid.Fragment;
    
    		import android.os.Bundle;
    		import android.support.v4.app.FragmentActivity;
    		
    		public class EjemploListFragment extends FragmentActivity {
    		
    			@Override
    			protected void onCreate(Bundle savedInstanceState) {
    				super.onCreate(savedInstanceState);
    				setContentView(R.layout.activity_ejemplo_list_fragment);
    			}
    		
    		}
    		

    De nuevo vemos que nuestra Activity no tiene nada importante, ya que la carga la soportan los Fragment que haremos a continuación, y la Activity nos sirve mas que nada como un simple contenedor de otras mini-actividades.

    Cabe destacar de nuevo, que mi Activity hereda de FragmentActivity, ya que así podré usar esta aplicaciones en dispositivos cuya API sea inferior a 11. De otro modo, si quisieramos que nuestra aplicación solo estuviera disponible para APIs mayores a 11, no tenemos que heredar de FragmentActivity, y por tanto, no deberemos importar el package de soporte.

  • Fragment1

    Ahora vamos a crear nuestro Fragment. Para ello vamos a crear una nueva clase java en nuestro package, o en otro que deseemos. Al igual que creamos nuestro Fragment vamos también a crear un layout para él, en el que mostraremos el aspecto que tendrá en ejecución:

    		<?xml version="1.0" encoding="utf-8"?>
    		<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    		    android:layout_width="match_parent"
    		    android:layout_height="match_parent"
    		    android:orientation="horizontal" >
    		
    		    <ListView
    		        android:id="@id/android:list"
    		        android:layout_width="0dp"
    		        android:layout_height="wrap_content"
    		        android:layout_weight="1"
    		        android:drawSelectorOnTop="true" />
    		
    		</LinearLayout>
    		

    Como vemos tenemos solo un elemento ListView, cuyo id es @id/android:list. Debemos establecer este id para que luego en nuestro código java no tengamos que instanciar la clase ListView, por lo que podemos llamar a los métodos básicos de los ListView sin tener que instanciarlo previamente.

    A continuación, nos dirigimos a nuestra clase y añadimos lo siguiente:

    		package sekth.droid.Fragment;
    
    		import android.os.Bundle;
    		import android.support.v4.app.ListFragment;
    		import android.view.LayoutInflater;
    		import android.view.View;
    		import android.view.ViewGroup;
    		import android.widget.ArrayAdapter;
    		import android.widget.ListView;
    		import android.widget.Toast;
    		
    		public class Fragment1 extends ListFragment {
    		
    			// Array de String que contiene nuestros queridos Sistemas Operativos
    			private String[] sistemas = { "Android", "Ubuntu", "Mac OSX", "Windows",
    					"Solaris", "Windows 8", "Ubuntu 12.04", "Windows Phone",
    					"Windows 7", "Kubuntu", "Ubuntu 12.10" };
    		
    			@Override
    			public View onCreateView(LayoutInflater inflater, ViewGroup container,
    					Bundle savedInstanceState) {
    				// TODO Auto-generated method stub
    				return inflater.inflate(R.layout.fragment1, container, false);
    			}
    		
    			@Override
    			public void onCreate(Bundle savedInstanceState) {
    				// TODO Auto-generated method stub
    				super.onCreate(savedInstanceState);
    		
    				// Establecemos el Adapter a la Lista del Fragment
    				setListAdapter(new ArrayAdapter<String>(getActivity(),
    						android.R.layout.simple_list_item_1, sistemas));
    			}
    		
    			@Override
    			public void onListItemClick(ListView l, View v, int position, long id) {
    				// TODO Auto-generated method stub
    				super.onListItemClick(l, v, position, id);
    		
    				// Mostramos un mensaje con el elemento pulsado
    				Toast.makeText(getActivity(), "Ha pulsado " + sistemas[position],
    						Toast.LENGTH_SHORT).show();
    			}
    		
    		}
    		

    Aquí vemos en un principio que nuestro Fragment1 no hereda de Fragment, sino de ListFragment, ya que es un Fragment mas especializado para esta tarea, teniendo acceso a métodos relacionados con los ListView y su uso.

    A continuación vamos a implantar los métodos onCreate, el cual inicializará la lista con los elementos del array que tenemos como variable de instancia y luego tenemos el método OnListItemClick, en el cual implantaremos todo el código necesario para que cuando se pulse un elemento del ListView, un aviso mediante la clase Toast nos muestre aquello que hemos pulsado.

    • onCreate:

      Nuestro ListFragment tiene un método onCreate, al igual que una Activity normal. Es en este método donde estableceremos el adapter al ListFragment:

      				@Override
      				public void onCreate(Bundle savedInstanceState) {
      					// TODO Auto-generated method stub
      					super.onCreate(savedInstanceState);
      			
      					// Establecemos el Adapter a la Lista del Fragment
      					setListAdapter(new ArrayAdapter<String>(getActivity(),
      							android.R.layout.simple_list_item_1, sistemas));
      				}
      				
    • onListItemClick:

      Como vemos, ya no tenemos que implementar la Interface que nos permite hacer este tipo de trabajo a la clase, sino que la superclase ListFragment ya tiene implementado este método, por tanto es mas cómodo a la hora de trabajar:

      				@Override
      				public void onListItemClick(ListView l, View v, int position, long id) {
      					// TODO Auto-generated method stub
      					super.onListItemClick(l, v, position, id);
      			
      					// Mostramos un mensaje con el elemento pulsado
      					Toast.makeText(getActivity(), "Ha pulsado " + sistemas[position],
      							Toast.LENGTH_SHORT).show();
      				}
      				

      Lo único que haremos, es mostrar un mensaje mediante la clase Toast para mostrar el item que hemos pulsado.

Nuestra aplicación ahora es funcional y podemos ejecutarla para verla en el emulador. Veremos que, como esperabamos, se nos muestran 2 ListFragment independientes el uno del otro, pero cada uno en un lado:

Dispositivo en Portrait:

PricipalPortrait PrincipalPortraitPulsado

Dispositivo en Landscape:

PrincipalLandscape

PrincipalLandscapePulsado

A continuación un vídeo en el que vemos la aplicación en ejecución:



Con esta entrada hemos cubierto un tipo de Fragment cuya tarea principal es tratar con Listas de objetos. Al igual que un ListView, también podemos adaptar esto a una Lista de elementos personalizados, que veremos en futuras entradas. Sin embargo, ya podemos ir añadiendo este tipo de enfoque a nuestros proyectos, y lo mas importante, es ver que cada Fragment actúa de manera independiente, y cada uno tiene su propio ciclo de vida, al igual que una Activity, esto es sumamente importante saberlo.

El código de este ejemplo podeis bajarlo de aquí.

Sin mas, cualquier aporte o corrección es bienvenido.

Saludos!!!

  • Jesús Guevara

    Hola :), doc lo que intento hacer es pasar datos de un fragment 1 a un fragment 2, ambos se encuentran en la misma activity. Podrian ayudarme a poder realizar esto…?

    • Buenas Jesús Guerava.

      Hay distintos modos de comunicarse entre Fragments que están en una misma actividad.

      • En esta entrada puedes ver como un fragment obtiene el valor de un TextView de otro fragment.
      • La otra manera es mediante el uso de un Interface que comparten con la Activity, tal como viene en Android Developers.

      Puede haber otros métodos pero ahora mismo no se me ocurre ninguno más, estos me han funcionado bien y tambien tiene que ver con el tipo de aplicación que se esté desarrollando.

      Espero que te sea de ayuda, cualquier cosa comunicamelo, y se busca una solución.

      Saludos y suerte!!!

  • jose

    LosFrangmentos xml tambien se mapean en elmanifest?

    • Buenas tardes Jose,

      No se mapean en el AndroidManifest, ya que residen en el interior de una Activity, la cual ya está mapeada en el 🙂

      Espero que te sea de ayuda.

      Saludos!