Si deseas 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 ViewModel
compartido o mediante el elemento Activity asociado. Dos objetos Fragment nunca deben comunicarse directamente.
La forma recomendada de comunicación entre fragmentos 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 estado nuevo se enviará al otro fragmento siempre que esté observando LiveData
desde el 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 genera 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.
Este es un ejemplo de comunicación entre objetos Fragment y Activity:
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 llamar al método onArticleSelected()
(o a otros métodos en la interfaz) mediante la instancia mCallback
de la interfaz OnHeadlineSelectedListener
para enviar mensajes a la actividad.
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 superior.
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 host puede entregar 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 generados 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... supportFragmentManager.commit { // Replace whatever is in the fragment_container view with a new Fragment, generated // from the FragmentFactory, and give it an argument for the selected article replace<ArticleFragment>(R.id.fragment_container, null, bundleOf(ArticleFragment.ARG_POSITION to position)) // add the transaction to the back stack so the user can navigate back addToBackStack(null) } } } }
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 de FragmentBasics.