Comunicándote con otros fragmentos

Esta lección te enseñará a

  1. Definir una interfaz
  2. Implementar una interfaz
  3. Enviar un mensaje a otro fragmento

También deberías leer

Para reutilizar los componentes Fragment, deberías desarrollar cada uno de ellos de forma totalmente autocontenida, como componentes modulares que definen su propia interfaz y comportamiento. Una vez hayas definido estos fragmentos reutilizables, puedes asociarlos con una Activity y conectarlos con la lógica de la aplicación para crear una interfaz de usuario compuesta.

A menudo querrás que un Fragment se comunique con otro, por ejemplo para cambiar el contenido basándote en un evento del usuario. Toda comunicación fragmento-a-fragmento se lleva a cabo a través de la actividad asociada. Dos fragmentos nunca deberían comunicarse directamente.

Definir una interfaz


Para permitir a un fragmento comunicarse con su actividad, puedes definir una interfaz en la clase Fragment e implementarla en la actividad. El fragmento captura la implementación de la interfaz durante su método de ciclo de vida onAttach() y puede luego llamar a los métodos de la interfaz para comunicarse con la actividad.

A continuación se muestra un ejemplo de comunicación entre un fragmento y una actividad:

public class HeadlinesFragment extends ListFragment {
    OnHeadlineSelectedListener mCallback;

    // La actividad contenedora debe implementar esta interfaz
    public interface OnHeadlineSelectedListener {
        public void onArticleSelected(int position);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        
        // Nos aseguramos de que la actividad contenedora haya implementado la
        // interfaz de retrollamada. Si no, lanzamos una excepción
        try {
            mCallback = (OnHeadlineSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " debe implementar OnHeadlineSelectedListener");
        }
    }
    
    ...
}

Ahora el fragmento puede enviar mensajes a la actividad llamando al método onArticleSelected() (o cualquier otro método de la interfaz) usando la instancia mCallback de la interfaz OnHeadlineSelectedListener.

Por ejemplo, el siguiente método del fragmento se llama cuando el usuario pulsa sobre un elemento de la lista. El fragmento usa la interfaz de retrollamada para enviar el evento a la actividad padre.

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        // Envía el evento a la actividad contenedora
        mCallback.onArticleSelected(position);
    }

Implementar una interfaz


Para recibir retrollamadas de eventos de un fragmento, la actividad que lo contiene debe implementar la interfaz definida en el fragmento.

Por ejemplo, la siguiente actividad implementa la interfaz del ejemplo anterior.

public static class MainActivity extends Activity
        implements HeadlinesFragment.OnHeadlineSelectedListener{
    ...
    
    public void onArticleSelected(int position) {
        // El usuario seleccionó el encabezado de un artículo del fragmento HeadlinesFragment
        // Haz algo para mostrar ese artículo
    }
}

Enviar un mensaje a otro fragmento


La actividad contenedora puede enviar mensajes a un fragmento capturando la instancia de Fragment con findFragmentById(), y llamando directamente a los métodos públicos del fragmento.

Por ejemplo, imagina que la actividad del ejemplo anterior contuviera otro fragmento que se utilizara para mostrar el elemento especificado por los datos devueltos en el método de retrollamada anterior. En ese caso, la actividad puede pasar la información recibida en el método de retrollamada al fragmento que mostrará el elemento:

public static class MainActivity extends Activity
        implements HeadlinesFragment.OnHeadlineSelectedListener{
    ...

    public void onArticleSelected(int position) {
        // El usuario seleccionó el encabezado de un artículo del fragmento HeadlinesFragment
        // Haz algo para mostrar ese artículo

        ArticleFragment articleFrag = (ArticleFragment)
                getSupportFragmentManager().findFragmentById(R.id.article_fragment);

        if (articleFrag != null) {
            // Si el fragmento de artículos está disponible, estamos en una interfaz
            // con dos paneles...

            // Llama a un método de ArticleFragment para actualizar su contenido
            articleFrag.updateArticleView(position);
        } else {
            // En caso contrario, estamos en una interfaz con un solo panel y tenemos
            // que intercambiar fragmentos...

            // Crea un fragmento y le pasa como argumento el artículo seleccionado
            ArticleFragment newFragment = new ArticleFragment();
            Bundle args = new Bundle();
            args.putInt(ArticleFragment.ARG_POSITION, position);
            newFragment.setArguments(args);
        
            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

            // Reemplazamos lo que haya en la vista fragment_container con este fragmento,
            // y añadimos la transacción a la pila de vuelta para que el usuario pueda volver
            transaction.replace(R.id.fragment_container, newFragment);
            transaction.addToBackStack(null);

            // Aplica la transacción
            transaction.commit();
        }
    }
}