개발을 하면서 앱이 점점 복잡해 질수록 Fragment끼리의 통신을 필요로 하게 된다.
사용자의 이벤트에 따라 올바르게 반응하거나 한가지 이벤트에 대해서 서로 다른 여러개의 Fragment가 반응해야 할 경우 공통의 채널이 필요로 하게 된다.
안드로이드에서는 보편적으로 두개의 방식을 제안한다.

Fragment끼리 데이터를 공유하는 방법에는 ViewModel 이라는 방식을 주로 채택했다.
하지만 개발 진행중 FragmentResultAPI를 이용한 방식을 알게 되었고 정리하기로 결정했다.

안드로이드 공식 문서에서는 두개의 사용처를 다음과 같이 구분해 놓았다.

영구 데이터를 모든 맞춤 API와 공유하려면 ViewModel
을 사용해야 합니다. 
[Bundle](https://developer.android.com/reference/android/os/Bundle)에 배치할 수 있는 데이터가 포함된 일회성 결과의 경우 Fragment Result API를 사용해야 합니다.


Fragment Manager

B에서 어떠한 데이터를 얻어 일회성인 번들의 형태로 A에게 넘겨 주고 싶을때 사용한다.
bundle을 생성하고 key값을 지정한 후 FragmentManager를 이용하여 데이터를 전달한다.

필자의 경우 커뮤니티 데이터를 통신 후 해당 데이터의 내용이 변경될때 별도의 서버 통신 없이 데이터에 대한 내용을 업데이트 해야하는 경우가 있었다.
업데이트 Fragment와 리스트 Fragment가 별도였고 해당 화면이 여러개의 Fragment로 구성되었기 때문에 ViewModel을 사용하려면 hierachy상 activityViewModel을 사용해야 했다.
하지만 ActivityViewModel을 사용하는 순간 커뮤니티에서 벗어날 때에도 계속해서 살아있기 때문에 이런 부분의 부담을 줄이기 위해서 선택했다.


사용법

  • A와 B의 공통적인 FragmentManager를 설정한다.
  • Fragment간의 통신(= Intent에서 사용하는 번들의 방법과 동일하다)처럼 Bundle을 생성한다.
  • 수신에는 리스너를 등록하고 발신에는 번들의 형태로 보내준다.

발신

button.setOnClickListener {
    val result = "result"
    // Use the Kotlin extension in the fragment-ktx artifact
    setFragmentResult("requestKey", bundleOf("bundleKey" to result))
}
  • 발신의 경우 setFragmentResult( “key”, 넘기고자 하는 데이터 번들)

수신

class ResultListenerFragment : Fragment() {
    var result : String? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // Use the Kotlin extension in the fragment-ktx artifact
        setFragmentResultListener("requestKey") { requestKey, bundle ->
            result = bundle.getString("bundleKey")
        }
    }
}
  • 수신의 경우 setFragmentResultListener(”key”){
    - 클로저의 형태로 requestKey와 bundle타입의 데이터가 넘어온다.
    }
  • 리스너를 등록하게 되면 수신의 Fragment의 onStart부분에서 실행되며 콜백의 형태로 리스너가 실행된다.
  • 리스너가 결과를 수신하게 되면 결과는 삭제되게 된다.(중복 실행 방지)
💡 **주의 주의해야할 점은 두개의 Fragment가 동일한 FragmentManager를 가져야 한다는 점이다. 예를들면 A, B, C, D라는 Fragment가 있다고 가정하자.

A —> B
—> C —> D
위와 같은 hierachy의 구조일때 D에서 B로 데이터를 넘겨주고 싶다면
공통 부모인 A의 FragmentManager를 다루어야 한다는 점이다.
parentFragmentManager를 이용하자.

사실 해당 방식은 자주 사용하진 않으며 ViewModel이라는 방식으로 주로 해결 할 수 있다.
하지만 본인처럼 특정 케이스에서 사용할 일이 생길 수 있기 때문에 한번쯤 알아두는 것이 유용할것이다.

React의 Redux처럼 사용하는 EventBus가 있다.
EventBus를 Global하게 사용하면 위와 같은 효과를 낼 수 있다.

profile
러닝커브를 따라서 등반중입니다.

0개의 댓글