Para reutilizar os componentes da IU de fragmento, você precisa construí-los como componentes completamente autossuficientes e modulares, que definam o próprio layout e comportamento. Assim que tiver definido esses fragmentos reutilizáveis, é possível associá-los a uma atividade e conectá-los à lógica do app para abranger a IU composta em sua totalidade.
Na maioria das vezes, é recomendável que um fragmento se comunique com outro, para, por exemplo, modificar o conteúdo baseado em um evento do usuário. Toda a comunicação entre fragmentos é feita por meio de um ViewModel
compartilhado ou pela atividade associada. Dois fragmentos nunca podem comunicar-se diretamente.
A maneira recomendada de estabelecer a comunicação entre fragmentos é criar um objeto ViewModel
compartilhado. Ambos os fragmentos podem acessar o ViewModel por meio da atividade contida. Os fragmentos podem atualizar dados no ViewModel e, se os dados forem expostos usando o LiveData
, o novo estado será enviado ao outro fragmento, desde que ele esteja observando o LiveData
no ViewModel
. Para saber como implementar esse tipo de comunicação, leia a seção "Compartilhar dados entre fragmentos" no guia do ViewModel.
Caso não consiga usar um ViewModel
compartilhado para realizar a comunicação entre seus fragmentos, é possível implementar um fluxo de comunicação manualmente usando interfaces.
Contudo, essa implementação é mais trabalhosa e não é facilmente reutilizável em outros fragmentos.
Definir uma interface
Para permitir que um fragmento se comunique com a atividade, você pode definir uma interface na classe Fragment e implementá-la dentro da atividade. O fragmento captura a implementação da interface durante o método de ciclo de vida onAttach()
e pode chamar os métodos de Interface para se comunicar com a atividade.
Este é um exemplo de comunicação de fragmento para atividade:
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); } } }
Agora o fragmento pode enviar mensagens à atividade, chamando o método onArticleSelected()
(ou outros métodos na interface) usando a instância mCallback
da interface OnHeadlineSelectedListener
.
Por exemplo, o método a seguir no fragmento é chamado quando o usuário clica em um item de lista. O fragmento usa a interface de callback para enviar o evento à atividade relacionada.
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); }
Implementação da interface
Para receber callbacks de evento do fragmento, a atividade que o hospeda precisa implementar a interface definida na classe do fragmento.
Por exemplo, a atividade a seguir implementa a interface do exemplo acima.
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 } }
Entregar uma mensagem a um fragmento
A atividade hospedeira pode enviar mensagens a um fragmento, capturando a instância Fragment
com findFragmentById()
. Em seguida, a atividade chama diretamente os métodos públicos do fragmento.
Por exemplo, imagine que a atividade exibida acima possa conter outro fragmento que é usado para exibir um item especificado pelos dados retornados no método de callback acima. Nesse caso, a atividade pode encaminhar a informação recebida no método de callback para outro fragmento que exibirá o item:
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 saber mais sobre a implementação de fragmentos, consulte Fragmentos. Saiba mais explorando o app de amostra FragmentBasics.