다른 프래그먼트와 통신

프래그먼트 UI 구성요소를 재사용하려면 각 구성요소를 자체 레이아웃 및 동작을 정의하는 완전히 독립된 모듈식 구성요소로 빌드해야 합니다. 이러한 재사용 가능한 프래그먼트를 정의한 후에는 활동 및 애플리케이션 로직과 연결하여 전반적인 복합 UI를 실현할 수 있습니다.

예를 들어 사용자 이벤트에 기반해 콘텐츠를 변경하려는 것과 같이 한 프래그먼트가 다른 프래그먼트와 통신하도록 하는 경우가 많습니다. 프래그먼트 간 모든 통신은 공유된 ViewModel이나 연결된 활동을 통해서 실행됩니다. 두 프래그먼트가 직접 통신해서는 안 됩니다.

프래그먼트 간 통신에 권장되는 방법은 공유된 ViewModel 객체를 만드는 것입니다. 두 프래그먼트는 포함된 활동을 통해 ViewModel에 액세스할 수 있습니다. 프래그먼트는 ViewModel 내 데이터를 업데이트할 수 있으며 LiveData를 통해 데이터가 노출되면 ViewModel의 LiveData를 관찰하고 있는 한 새로운 상태가 다른 프래그먼트로 푸시됩니다. 이와 같은 통신의 구현 방법을 확인하려면 ViewModel 가이드의 '프래그먼트 간 데이터 공유' 섹션을 읽어보세요.

공유된 ViewModel을 사용하여 프래그먼트 간 통신을 할 수 없다면 인터페이스를 사용하여 통신 흐름을 수동으로 구현해도 됩니다. 그러나 이 방법은 구현에 더 많은 작업이 필요하고 다른 프래그먼트에 재사용하기도 쉽지 않습니다.

인터페이스 정의

프래그먼트가 활동과 통신하게 하려면 프래그먼트 클래스에서 인터페이스를 정의하고, 이를 활동에서 구현하면 됩니다. 프래그먼트는 onAttach() 수명 주기 메서드 중 인터페이스 구현을 캡처한 다음 활동과 통신하기 위해 인터페이스 메서드를 호출할 수 있습니다.

다음은 프래그먼트와 활동 간 통신의 예입니다.

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

        // ...
    }
    

자바

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

자바

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

자바

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

인터페이스 구현

프래그먼트에서 이벤트 콜백을 수신하려면 이를 호스팅하는 활동이 프래그먼트 클래스에 정의된 인터페이스를 구현해야 합니다.

예를 들어 다음 활동은 위 예의 인터페이스를 구현합니다.

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

자바

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

자바

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

프래그먼트 구현에 관한 자세한 내용은 프래그먼트를 참조하세요. 관련 샘플 앱을 탐색하여 자세히 알아볼 수도 있습니다.