Google은 흑인 공동체를 위한 인종 간 평등을 진전시키기 위해 노력하고 있습니다. Google에서 어떤 노력을 하고 있는지 확인하세요.

프래그먼트 간 데이터 전달

프래그먼트 1.3.0-alpha04부터 각 FragmentManagerFragmentResultOwner를 구현합니다. 즉, FragmentManager는 프래그먼트 결과의 중앙 저장소 역할을 할 수 있습니다. 이번 변경을 통해 프래그먼트가 서로 직접 참조할 필요 없이 프래그먼트 결과를 설정하고 결과를 수신하여 개별 프래그먼트 간에 통신할 수 있습니다.

프래그먼트 B에서 프래그먼트 A로 데이터를 다시 전달하려면 우선, 결과를 수신하는 프래그먼트인 프래그먼트 A에서 결과 리스너를 설정합니다. 다음 예와 같이 프래그먼트 A의 FragmentManager에서 setFragmentResultListener() API를 호출합니다.

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // Use the Kotlin extension in the fragment-ktx artifact
    setResultListener("requestKey") { key, bundle ->
        // We use a String here, but any type that can be put in a Bundle is supported
        val result = bundle.getString("bundleKey")
        // Do something with the result...
    }
}

자바

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getParentFragmentManager().setFragmentResultListener("key", this, new FragmentResultListener() {
        @Override
        public void onFragmentResult(@NonNull String key, @NonNull Bundle bundle) {
            // We use a String here, but any type that can be put in a Bundle is supported
            String result = bundle.getString("bundleKey");
            // Do something with the result...
        }
    });
}
프래그먼트 b는 프래그먼트 관리자를 사용하여 프래그먼트 A에 데이터를 전송합니다.
그림 1. FragmentManager를 사용하여 프래그먼트 A로 데이터를 전송하는 프래그먼트 B

결과를 생성하는 프래그먼트인 프래그먼트 B에서 동일한 requestKey를 사용하여 동일한 FragmentManager에 결과를 설정해야 합니다. 이 작업은 setFragmentResult() API를 사용하여 실행할 수 있습니다.

Kotlin

button.setOnClickListener {
    val result = "result"
    // Use the Kotlin extension in the fragment-ktx artifact
    setResult("requestKey", bundleOf("bundleKey" to result))
}

자바

button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Bundle result = new Bundle();
        result.putString("bundleKey", "result");
        getParentFragmentManager().setFragmentResult("requestKey", result);
    }
});

그러면 프래그먼트 A는 결과를 수신하고 STARTED 상태가 되면 리스너 콜백을 실행합니다.

주어진 키에는 단일 리스너와 결과만 있을 수 있습니다. 동일한 키에 setResult()를 두 번 이상 호출하면 프래그먼트 B가 백 스택에서 사라지기 전에 시스템에서 가장 최근 결과를 프래그먼트 A에 전송합니다. 결과를 수신할 관련 리스너 없이 결과를 설정하면 결과는 동일한 키로 리스너를 설정할 때까지 FragmentManager에 저장됩니다. 리스너의 프래그먼트는 STARTED 상태여야 프래그먼트가 결과를 수신할 수 있습니다. 리스너가 결과를 수신하고 onFragmentResult() 콜백을 실행하면 결과는 삭제됩니다. 이 동작에는 다음 두 가지 의미가 있습니다.

  • 백 스택의 프래그먼트는 표시되어 STARTED 상태가 될 때까지 결과를 수신하지 않습니다.
  • 결과를 수신하는 프래그먼트가 STARTED 상태인 경우 결과가 설정되면 리스너의 콜백이 즉시 실행됩니다.

상위 및 하위 프래그먼트 간 결과 전달

하위 프래그먼트의 결과를 상위 요소로 전달하려면 상위 프래그먼트가 setFragmentResultListener()를 호출할 때 getParentFragmentManager() 대신 getChildFragmentManager()를 사용해야 합니다.

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // We set the listener on the child fragmentManager
    childFragmentManager.setResultListener("requestKey") { key, bundle ->
        val result = bundle.getString("bundleKey")
        // Do something with the result..
    }
}

자바

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // We set the listener on the child fragmentManager
    getChildFragmentManager().setFragmentResultListener("key", this, new FragmentResultListener() {
        @Override
        public void onFragmentResult(@NonNull String key, @NonNull Bundle bundle) {
            String result = bundle.getString("bundleKey");
            // Do something with the result..
        }
    });
}
하위 프래그먼트는 프래그먼트 관리자를 사용하여 상위 요소에 결과를 전송할 수 있습니다.
그림 2. FragmentManager를 사용하여 상위 요소에 결과를 전송할 수 있는 하위 프래그먼트

하위 프래그먼트는 FragmentManager에 결과를 설정합니다. 그러면 다음과 같이 프래그먼트가 STARTED 상태가 되면 상위 요소에서 결과를 수신합니다.

Kotlin

button.setOnClickListener {
    val result = "result"
    // Use the Kotlin extension in the fragment-ktx artifact
    setResult("requestKey", bundleOf("bundleKey" to result))
}

자바

button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Bundle result = new Bundle();
        result.putString("bundleKey", "result");

        // The child fragment needs to still set the result on its parent fragment manager
        getParentFragmentManager().setFragmentResult("requestKey", result);
    }
});

프래그먼트 결과 테스트

FragmentScenario를 사용하여 setFragmentResult()setFragmentResultListener() 호출을 테스트합니다. launchFragmentInContainer 또는 launchFragment를 사용하여 테스트 중인 프래그먼트의 시나리오를 만들고 테스트 중이 아닌 메서드를 수동으로 호출합니다.

setResultListener()를 테스트하려면 setResultListener()를 호출하는 프래그먼트로 시나리오를 만듭니다. 그런 다음 setResult()를 직접 호출하여 다음과 같이 결과를 확인합니다.

@Test
fun testFragmentResultListener() {
    val scenario = launchFragmentInContainer<ResultListenerFragment>()
    scenario.onFragment { fragment ->
        val expectedResult = "result"
        fragment.parentFragmentManagager.setResult("requestKey", bundleOf("bundleKey" to expectedResult))
        assertThat(fragment.result).isEqualTo(expectedResult)
    }
}

class ResultListenerFragment : Fragment() {
    var result : String? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // Use the Kotlin extension in the fragment-ktx artifact
        setResultListener("requestKey") { key, bundle ->
            result = bundle.getString("bundleKey")
        }
    }
}

setResult()를 테스트하려면 setResult()를 호출하는 프래그먼트로 시나리오를 만듭니다. 그런 다음 setResultListener()를 직접 호출하여 다음과 같이 결과를 확인합니다.

@Test
fun testFragmentResult() {
    val scenario = launchFragmentInContainer<ResultFragment>()
    lateinit var actualResult: String?
    scenario.onFragment { fragment ->
        fragment.parentFragmentManagager.setResultListener("requestKey") { key, bundle ->
            actualResult = bundle.getString("bundleKey")
        }
    }
    onView(withId(R.id.result_button)).perform(click())
    assertThat(actualResult).isEqualTo("result")
}

class ResultFragment : Fragment(R.layout.fragment_result) {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        view.findViewById(R.id.result_button).setOnClickListener {
            val result = "result"
            // Use the Kotlin extension in the fragment-ktx artifact
            setResult("requestKey", bundleOf("bundleKey" to result))
        }
    }
}