Fragment Result API : 동일한 키로 Fragment result 관리하기

Pgopose
5 min readJun 6, 2021

--

Fragment 1.3.0-alpha04 부터 FragmentManagerFragmentResultOwner를 구현합니다.
FragmentManagerrequestKey에 해당하는 bundle을 등록하고 이를 조회하는 방법으로 Fragment 사이에서 결과를 전달할 수 있게 되었습니다.

특히 FragmentManager로의 명시적인 참조 없이 Fragment.setFragmentResult(), Fragment.setFragmentResultListener() 을 통해 현재 Fragment와 상호작용하는 FragmentManager에 result를 등록하고 Key에 해당하는 결과를 가져올 수 있어서 간단히 이용할 수 있습니다.

공식홈페이지에서는 onCreate() callback func에서 등록해주고 사용하는 모습을 볼 수 있습니다.

공식 홈페이지 예제

구글에서 제공하는 샘플이니 그대로 사용할 수 있을까요?

일반적으로 key-value 쌍 구조를 구현하는 과정에서, Producer-Consumer 결합도를 낮추기위해 Key를 Producer에 의존하게 구현하는 경우들이 많습니다.

샘플대로라면 Producer base Key 관리 정책을 이용할때 문제점이 발생할 수 있습니다.

어떤 시나리오에서 문제가 발생하는지 예시를 들어보겠습니다.

각각의 이미지는 아래의 플로우를 설명합니다.

1: A→B→C⇒B(resultC)

2: A→C⇒A(resultC)

(각 A, B, C는 Fragment를 의미합니다. 화살표는 Fragment transection을 나타내며, ⇒ 는 result 반환하는 pop back stack transection 입니다.)

Result 전달 과정을 간략하면, ResultFragment 진입 전에 ResultFragment name을 Key로 setFragmentResultListener()를 호출하며 ResultFragment 클래스는 Key로 setFragmentResult()를 호출하고 종료합니다.

위의 1,2의 시나리오는 구글 샘플로도 정상적으로 통과합니다.
하지만 다음의 시나리오는 어떻게 동작할까요?

3: A→B→C⇒B(resultC)⇒A→C⇒A(resultC?)

A는 C로부터 결과를 받아오지 못합니다.

FragmentManager는 requestKey를 Map으로 관리한다.

3번 시나리오의 실패 이유는 FragmentManager.setFragmentResultListener() 세부 구현을 살펴 보면 알 수 있습니다.

FragmentManager.setFragmentResultListener()의 세부구현에는 아래와 같은 코드가 있습니다.

mResultListeners.put() method를 주목해야함

fragmentResultListener를 등록하는 mResultListeners는 Map 구조체로, put() 호출 시 동일한 requestKey로 등록된 이전 listener를 대체합니다.

3번 시나리오의 경우 B Fragment의 onCreate() 콜백에서 fragmentResultListener를 대체한 상태기 때문에 A Fragment의 resultListener가 동작하지 않는 것입니다.

그럼 어떻게해야 반환측에서 사용하는 requestKey를 유지하면서도 유연한 result 반환을 할 수 있을까요?

onViewCreated() callback에서 listener 등록하기

간단하게 onCreate()에서 등록하던 fragmentResultListener init 시점을 onViewCreated()로 옮기는 것으로 해결됩니다.

requestKey를 Map으로 관리한다는 점에서 착안하여 항상 최상단에 위치한 FragmentfragmentResultListener 를 유효하게하면 위의 시나리오 문제를 해결할 수 있습니다.

이 방법과 별개로, frament 전환 과정에서 backstack을 이용하지 않는 방법이 있긴합니다. 다만, fragment result를 위해 fragment navigation에 대한 구현을 강제하는 방법이라 권하지는 않습니다.
(이에 대한 내용은 아래 깃허브에서 좀 더 자세하게 설명합니다.)

정리

Fragment Result API에서 중복된 키를 어떻게 관리하는지 알아봤습니다.
위의 테스트를 직접 해볼 수 있는 깃허브 주소를 공유하면서 포스트를 마무리하겠습니다.

깃허브 프로젝트에는 일부 보완된 설명을 추가했으니 가볍게 읽어 보셔도 도움이 되실 듯 합니다.

--

--