The Android Developer Challenge is back! Submit your idea before December 2.

Cómo comunicar contenido con otros fragmentos

Para volver a usar los componentes de la IU de objetos Fragment, debes crear cada uno como un componente modular completamente independiente que defina su propio diseño y comportamiento. Una vez que hayas definido esos objetos Fragment reutilizables, podrás asociarlos con un objeto Activity y conectarlos a la lógica de la aplicación para comprender la IU completa de la composición.

Con frecuencia, querrás que un objeto Fragment se comunique con otro; por ejemplo, para cambiar el contenido en función de un evento de usuario. Toda la comunicación entre objetos Fragment se realiza mediante un elemento ViewModel compartido o mediante el objeto Activity asociado. Dos objetos Fragment nunca deben comunicarse directamente.

La forma recomendada de comunicación en este caso es crear un objeto ViewModel compartido. Ambos fragmentos pueden acceder al objeto ViewModel mediante el objeto Activity que los contiene. Los objetos Fragment pueden actualizar los datos dentro del ViewModel y, si los datos se exponen mediante LiveData, el nuevo estado se enviará al otro fragmento siempre que esté observando LiveData desde ViewModel. Para ver cómo implementar este tipo de comunicación, consulta la sección "Cómo compartir los datos entre fragmentos" en la guía de ViewModel.

Si no puedes utilizar un ViewModel compartido para la comunicación entre objetos Fragment, puedes implementar un flujo de comunicación manualmente mediante interfaces. Sin embargo, esto da como resultado un mayor esfuerzo de implementación y no puede reutilizarse en otros objetos Fragment con facilidad.

Cómo definir una interfaz

Para permitir que un objeto Fragment se comunique con su Activity, puedes definir una interfaz en la clase Fragment y luego implementarla dentro del objeto Activity. El objeto Fragment captura la implementación de la interfaz durante su método de ciclo de vida onAttach() y luego puede llamar a los métodos de la interfaz para comunicarse con el objeto Activity.

Aquí te mostramos un ejemplo de comunicación de fragmento a actividad:

HeadlinesFragment

Kotlin

    class HeadlinesFragment : ListFragment() {
        internal var callback: OnHeadlineSelectedListener

        fun setOnHeadlineSelectedListener(callback: OnHeadlineSelectedListener) {
            this.callback = callback
        }

        // This interface can be implemented by the Activity, parent Fragment,
        // or a separate test implementation.
        interface OnHeadlineSelectedListener {
            fun onArticleSelected(position: Int)
        }

        // ...
    }
    

Java

    public class HeadlinesFragment extends ListFragment {
        OnHeadlineSelectedListener callback;

        public void setOnHeadlineSelectedListener(OnHeadlineSelectedListener callback) {
            this.callback = callback;
        }

        // This interface can be implemented by the Activity, parent Fragment,
        // or a separate test implementation.
        public interface OnHeadlineSelectedListener {
            public void onArticleSelected(int position);
        }

        // ...
    }
    

MainActivity

Kotlin

    class MainActivity : Activity(), HeadlinesFragment.OnHeadlineSelectedListener {
        // ...

        fun onAttachFragment(fragment: Fragment) {
            if (fragment is HeadlinesFragment) {
                fragment.setOnHeadlineSelectedListener(this)
            }
        }
    }
    

Java

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

        @Override
        public void onAttachFragment(Fragment fragment) {
            if (fragment instanceof HeadlinesFragment) {
                HeadlinesFragment headlinesFragment = (HeadlinesFragment) fragment;
                headlinesFragment.setOnHeadlineSelectedListener(this);
            }
        }
    }
    

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

Por ejemplo, se llama al siguiente método en el fragmento cuando el usuario hace clic en un elemento de la lista. El fragmento utiliza la interfaz de devolución de llamada para entregar el evento a la actividad primaria.

Kotlin

    override fun onListItemClick(l: ListView, v: View, position: Int, id: Long) {
        // Send the event to the host activity
        callback.onArticleSelected(position)
    }
    

Java

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        // Send the event to the host activity
        callback.onArticleSelected(position);
    }
    

Cómo implementar la interfaz

Para recibir devoluciones de llamadas de eventos por parte del fragmento, la actividad que lo aloja debe implementar la interfaz definida en la clase de fragmento.

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

Kotlin

    class MainActivity : Activity(), HeadlinesFragment.OnHeadlineSelectedListener {
        ...

        fun onArticleSelected(position: Int) {
            // The user selected the headline of an article from the HeadlinesFragment
            // Do something here to display that article
        }
    }
    

Java

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

        public void onArticleSelected(int position) {
            // The user selected the headline of an article from the HeadlinesFragment
            // Do something here to display that article
        }
    }
    

Cómo enviar un mensaje a un fragmento

La actividad anfitriona puede enviar mensajes a un fragmento mediante la captura de la instancia Fragment con findFragmentById() y luego llamar directamente a los métodos públicos del fragmento.

Por ejemplo, imagina que la actividad que se mostró anteriormente contiene otro fragmento que se usa para mostrar el elemento especificado por los datos devueltos en el método de devolución de llamada anterior. En ese caso, la actividad puede comunicar la información recibida en el método de devolución de llamada al otro fragmento que mostrará el elemento de la siguiente manera:

Kotlin

    class MainActivity : Activity(), HeadlinesFragment.OnHeadlineSelectedListener {
        ...

        fun onArticleSelected(position: Int) {
            // The user selected the headline of an article from the HeadlinesFragment
            // Do something here to display that article

            val articleFrag = supportFragmentManager.findFragmentById(R.id.article_fragment) as ArticleFragment?

            if (articleFrag != null) {
                // If article frag is available, we're in two-pane layout...

                // Call a method in the ArticleFragment to update its content
                articleFrag.updateArticleView(position)
            } else {
                // Otherwise, we're in the one-pane layout and must swap frags...
                // Create fragment and give it an argument for the selected article
                val newFragment = ArticleFragment()
                val args = Bundle()
                args.putInt(ArticleFragment.ARG_POSITION, position)
                newFragment.arguments = args

                val transaction = supportFragmentManager.beginTransaction()

                // Replace whatever is in the fragment_container view with this fragment,
                // and add the transaction to the back stack so the user can navigate back
                transaction.replace(R.id.fragment_container, newFragment)
                transaction.addToBackStack(null)

                // Commit the transaction
                transaction.commit()
            }
        }
    }
    

Java

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

        public void onArticleSelected(int position) {
            // The user selected the headline of an article from the HeadlinesFragment
            // Do something here to display that article

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

            if (articleFrag != null) {
                // If article frag is available, we're in two-pane layout...

                // Call a method in the ArticleFragment to update its content
                articleFrag.updateArticleView(position);
            } else {
                // Otherwise, we're in the one-pane layout and must swap frags...

                // Create fragment and give it an argument for the selected article
                ArticleFragment newFragment = new ArticleFragment();
                Bundle args = new Bundle();
                args.putInt(ArticleFragment.ARG_POSITION, position);
                newFragment.setArguments(args);

                FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

                // Replace whatever is in the fragment_container view with this fragment,
                // and add the transaction to the back stack so the user can navigate back
                transaction.replace(R.id.fragment_container, newFragment);
                transaction.addToBackStack(null);

                // Commit the transaction
                transaction.commit();
            }
        }
    }
    

Para obtener más información sobre la implementación de objetos Fragment, consulta Fragmentos. También puedes obtener más información explorando la app de muestra correspondiente.