Android 11 デベロッパー プレビュー 2 が公開されました。ぜひお試しのうえ、フィードバックをお寄せください

他のフラグメントとの通信

Fragment UI コンポーネントを再利用するには、各コンポーネントを、自身のレイアウトや動作を定義する自己完結型モジュラー コンポーネントとしてビルドする必要があります。一度再利用可能な形で定義されたフラグメントは、アクティビティに関連付けてアプリロジックに接続でき、これにより複合 UI 全体が実現します。

たとえば、ユーザー イベントに基づいてコンテンツを変える場合など、1 つのフラグメントから他のフラグメントを利用したい場合もあります。フラグメント間のやり取りはすべて、共有 ViewModel または関連付けられたアクティビティを介して行われます。2 つのフラグメントが直接やり取りすることはありません。

フラグメント間の通信は、共有 ViewModel オブジェクトを作成して行うことをおすすめします。両方のフラグメントが含まれるアクティビティを介して ViewModel にアクセスできます。フラグメントは ViewModel 内でデータを更新できます。そのデータが LiveData を使用して公開されている場合、ViewModel から LiveData が監視されていれば、新しい状態は他のフラグメントにプッシュされます。この種の通信を実装する方法については、ViewModel ガイドの「フラグメント間でデータを共有する」をご覧ください。

フラグメント間の通信に共有 ViewModel を使用できない場合は、インターフェースを使用して手動で通信フローを実装できます。ただし、この方法で実装するにはさらに多くの作業が必要になり、他のフラグメントでの再利用も容易ではありません。

インターフェースを定義する

フラグメントがアクティビティとやり取りするには、Fragment クラス内でインターフェースを定義し、それをアクティビティ内に実装します。onAttach() ライフサイクル メソッド中にフラグメントがインターフェースの実装をキャプチャし、Interface メソッドを呼び出してアクティビティとやり取りできます。

フラグメントとアクティビティのやり取りの例を以下に示します。

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);
            }
        }
    }
    

これで、フラグメントは OnHeadlineSelectedListener インターフェースの mCallback インスタンスを使用して onArticleSelected() メソッド(またはインターフェース内の他のメソッド)を呼び出すことで、アクティビティにメッセージを配信できるようになります。

たとえば、ユーザーがリスト項目をクリックすると、フラグメントの次のメソッドが呼び出されます。フラグメントはコールバック インターフェースを使用してイベントを親アクティビティに配信します。

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);
    }
    

インターフェースを実装する

フラグメントからイベントのコールバックを受信するには、それをホストするアクティビティは Fragment クラスで定義されたインターフェースを実装する必要があります。

たとえば、次のアクティビティでは前出の例のインターフェースを実装します。

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
        }
    }
    

フラグメントにメッセージを配信する

ホスト アクティビティは、findFragmentById() を使用して Fragment インスタンスをキャプチャすることでフラグメントにメッセージを配信し、フラグメントのパブリック メソッドを直接呼び出すことができます。

たとえば、上記のアクティビティに別のフラグメントが含まれていて、そのフラグメントを使って上記のコールバック メソッドで返されたデータによって指定された項目を表示するとします。この場合、アクティビティは、コールバック メソッドで受信した情報を、項目を表示する別のフラグメントに渡すことができます。

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();
            }
        }
    }
    

フラグメントの実装について詳しくは、フラグメントをご覧ください。関連するサンプルアプリで詳細を確認することもできます。