[Android] 프래그먼트간 데이터 전달 - Fragment Result API

Fragment1 에서 글을 추가하는 동작을 구현중, Activity를 거쳐서 다른 Fragmet2에서 이 데이터를 받아와야하는 문제가 생겼다.

데이터를 주고받는데 레지스터포 액티비티리저트 를 사용하는등의 여러가지 방법이 있지만 고심끝에 Fragment Result API 를 사용해 전달 해 보기로 하였다.

1) Fragment Result API

img

💡 문제해결 방법

  1. fragment result 리스너 등록
  2. 바텀시트를 올린다
  3. 바텀시트에서 리저트로 클릭한 타입을 보낸다.
  4. 1번에서 등록한 리스너에서 3번에서 받은 타입을 받은후 등록 액티비티를 올린다.(레지스터포 액티비티리저트)

값을 받은다음 화면을 올리는 흐름으로 구현 해 보았다!


2) AFragment에서 setFragmentResultListener 등록

setFragmentResultListener("requestKey") { requestKey, bundle ->
//결과 값을 받는곳입니다.
val result = bundle.getString("bundleKey")}
  • 프래그먼트 B에서 프래그먼트 A로 데이터를 다시 전달하려면 우선, 결과를 수신하는 프래그먼트인 프래그먼트 A에서 결과 리스너를 설정한다.
  • 값은상수로 입력해주면 더 좋다!

3) AFragment에서 BFragment 올라오도록 하기

fabAdd.setOnClickListener {
            val teamAddCategory = TeamAddCategory()
            teamAddCategory.show(childFragmentManager, teamAddCategory.tag)

            setFragmentResultListener(FRAGMENT_REQUEST_KEY) { _, bundle ->
                Log.d("teamFragment","startActivity")
                when (bundle.getString(FRAGMENT_RETURN_TYPE)) {
                    TeamAddCategory.RETURN_TYPE_RECRUITMENT -> {
                        
                        )
                        
                    }

                    TeamAddCategory.RETURN_TYPE_APPLICATION -> {
                        
                        )
                       
                }

            
  • 본인은 FragmentA(받아야 할 곳) <–전달–> FragmentB(글 작성 진입) <–전달–> Activity(글작성페이지)-야 할 곳)
  • 위와 같은 순서로 화면이 만들어졌기때문에, 먼저 화면을 띄워주고 데이터를 전달할 수 있도록 구현하였다.

  • 먼저 A화면에서 B화면이나오는 동작을 만들어줬다.

4) BFragment에서 AFragment 로 리턴할값을 설정하기

private fun initView() = with(binding) {
        // 여기서 Fragment Result Listener로 값을 return한다.
        btnRecruitment.setOnClickListener {
            //용병 모집
            setFragmentResult(FRAGMENT_REQUEST_KEY,bundleOf( FRAGMENT_RETURN_TYPE to RETURN_TYPE_RECRUITMENT))
            dismiss()
            Log.d("teamAddCaregory","close bottonseet")
        }

        btnApplication.setOnClickListener {
            //용병 신청
            setFragmentResult(FRAGMENT_REQUEST_KEY,bundleOf(FRAGMENT_RETURN_TYPE to RETURN_TYPE_APPLICATION))
            dismiss()
            Log.d("teamAddCaregory","close bottonseet")
        }
    }
  • Activity 진입 타입을 나눠줬기때문에 액티비티에서 어떤값을 리턴 해줄것인지 정해주었다.

  • 버튼을누르면 바로 화면이 종료되도록 dismiss() 를 사용했다.

5) AFragment 돌아와 액티비티 실행시켜주기

private val addContentLauncher =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
            val teamModel = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                result.data?.getParcelableExtra(
                    TeamAddActivity.EXTRA_TEAM_MODEL,
                    TeamItem::class.java
                )
            } else {
                result.data?.getParcelableExtra(
                    TeamAddActivity.EXTRA_TEAM_MODEL,
                )
            }
            val teamType = result.data?.getStringExtra(TeamAddActivity.EXTRA_TEAM_ENTRY_TYPE)

            setAddContent(teamModel, teamType)
        }
...

fabAdd.setOnClickListener {
            val teamAddCategory = TeamAddCategory()
            teamAddCategory.show(childFragmentManager, teamAddCategory.tag)

            setFragmentResultListener(FRAGMENT_REQUEST_KEY) { _, bundle ->
                Log.d("teamFragment","startActivity")
                when (bundle.getString(FRAGMENT_RETURN_TYPE)) {
                    TeamAddCategory.RETURN_TYPE_RECRUITMENT -> {
                        val intent = TeamAddActivity.newIntentForAddRecruit(
                            requireContext(),
                            TeamAddType.RECRUIT.name
                        )
                        Log.d("teamFragment","result")
                        addContentLauncher.launch(intent)
                    }

                    TeamAddCategory.RETURN_TYPE_APPLICATION -> {
                        val intent = TeamAddActivity.newIntentForAddApplication(
                            requireContext(),
                            TeamAddType.APPLICATION.name
                        )
                        Log.d("teamFragment","result")
                        addContentLauncher.launch(intent)
                    }
                }

            }
           
        }
  • 다시 AFragment 돌아와 result= getstring으로 리턴값을 받은후 액티비티 실행시켜주었다.
  • 데이터는 registerForActivityResult 를 사용해 Model,Type을 받아 글이 등록되도록 해주었다.

문제 : 설정한리스너가 콜백이 안되는 오류 발생

fabAdd.setOnClickListener {
            val teamAddCategory = TeamAddCategory()
            teamAddCategory.show(**childFragmentManager**, teamAddCategory.tag)
            //같은 프래그먼트의 childFragmentManager를 쓰면 같은 라이프사이클을 사용 해야함
            childFragmentManager.setFragmentResultListener(FRAGMENT_REQUEST_KEY,viewLifecycleOwner) { key, bundle ->
                val result = bundle.getString(FRAGMENT_RETURN_TYPE)
  • 같은 프래그먼트를 사용하면 같은 라이프사이클을 이용해야 하기때문에!!! childFragmentManager를 지정해 줘야한다.

© 2023. All rights reserved.

AgileCatch