FragmentResultApi 란?

쓰리원·2022년 6월 15일
0
post-thumbnail

1. 기존 Listener 방식

나중에 작성 예정

2. Fragment Result API란?

두 프래그먼트 간에 또는 프래그먼트와 호스트 활동 간에 일회성 값을 전달해야 할 수 있습니다. 예를 들어 QR 코드를 읽고 이전 프래그먼트로 데이터를 다시 전달하는 프래그먼트가 있을 수 있습니다. Fragment 1.3.0-alpha04부터 각 FragmentManager는 FragmentResultOwner를 구현합니다.

즉, FragmentManager는 프래그먼트 결과의 중앙 저장소 역할을 할 수 있습니다. 이번 변경으로 구성요소가 서로를 직접 참조하지 않아도 프래그먼트 결과를 설정하고 이러한 결과를 수신 대기하여 구성요소가 서로 통신할 수 있습니다.

자세한 예시 상황

  1. FragmentA에서 게시글 리스트를 출력한다.
  1. FragmentA의 리스트 중 게시글 1개를 클릭하면 그 게시글에 대한 상세 내용을 보여주는 FragmentB를 출력한다.
  1. FragmentB에서 그 게시글을 삭제,수정한다는 이벤트을 활성화하고 FragmentB가 닫히고 FragmentA가 나타난다.
  1. FragmentA로 돌아왔을 때 삭제한 게시글이 없는 리스트, 혹은 수정된 리스트가 출력된다.

3. 프래그먼트 간 결과 전달

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

Fragment A - 결과 값을 받는다
Fragment B - 결과 값을 보낸다

즉, FragmentB에서 FragmentA의 데이터 구성을 바꾸고 있는 것 입니다.

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // Use the Kotlin extension in the fragment-ktx artifact
    setFragmentResultListener("requestKey") { requestKey, 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
    }
}

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

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

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

주어진 키에는 단일 리스너와 결과만 있을 수 있습니다. 동일한 키에 setFragmentResult()를 두 번 이상 호출하는 경우 그리고 리스너가 STARTED 상태가 아닌 경우 시스템은 대기 중인 결과를 업데이트된 결과로 바꿉니다.

결과를 수신할 관련 리스너 없이 결과를 설정하면 결과는 동일한 키로 리스너를 설정할 때까지 FragmentManager에 저장됩니다. 리스너가 결과를 수신하고 onFragmentResult() 콜백을 실행하면 결과는 삭제됩니다. 이 동작에는 다음 두 가지 의미가 있습니다.

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

(위 요약이 핵심이라고 볼 수 있습니다)

4. 예제 코드

1. RecieverFragment.kt

class RecieverFragment : Fragment() {

    private lateinit var binding: FragmentRecieverBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = FragmentRecieverBinding.inflate(layoutInflater)

        setFragmentResultListener("requestKey") { requestKey, bundle ->
            bundle.getString("bundleKey")?.let {
                binding.textView.setText(it)
            }
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return binding.root
    }
}

2. SenderFragment.kt

class SenderFragment : Fragment() {

    private lateinit var binding: FragmentSenderBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = FragmentSenderBinding.inflate(layoutInflater)
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return binding.root
    }

    override fun onResume() {
        super.onResume()
        binding.btnYes.setOnClickListener {
            val result = "Yes"
            val bundle = bundleOf("bundleKey" to result)
            setFragmentResult("requestKey", bundle)
        }
        binding.btnNo.setOnClickListener {
            val result = "No"
            val bundle = bundleOf("bundleKey" to result)
            setFragmentResult("requestKey", bundle)
        }
    }
}

예제 코드 : https://github.com/ilil1/FragmentResultApi

5. reference

https://developer.android.com/guide/fragments/communicate?hl=ko
https://pluu.github.io/blog/android/2020/05/04/fragment-result/

profile
가장 아름다운 정답은 서로의 협업안에 있다.

0개의 댓글