Comunicar-se com outros fragmentos

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.