[Android] 프래그먼트간 데이터 전달 - Fragment Result API
- 1) Fragment Result API
- 2) AFragment에서 setFragmentResultListener 등록
- 3) AFragment에서 BFragment 올라오도록 하기
- 4) BFragment에서 AFragment 로 리턴할값을 설정하기
- 5) AFragment 돌아와 액티비티 실행시켜주기
- 문제 : 설정한리스너가 콜백이 안되는 오류 발생
Fragment1 에서 글을 추가하는 동작을 구현중, Activity를 거쳐서 다른 Fragmet2에서 이 데이터를 받아와야하는 문제가 생겼다.
데이터를 주고받는데 레지스터포 액티비티리저트 를 사용하는등의 여러가지 방법이 있지만 고심끝에 Fragment Result API 를 사용해 전달 해 보기로 하였다.
1) Fragment Result API
💡 문제해결 방법
- fragment result 리스너 등록
- 바텀시트를 올린다
- 바텀시트에서 리저트로 클릭한 타입을 보낸다.
- 1번에서 등록한 리스너에서 3번에서 받은 타입을 받은후 등록 액티비티를 올린다.(레지스터포 액티비티리저트)
값을 받은다음 화면을 올리는 흐름으로 구현 해 보았다!
2) AFragment에서 setFragmentResultListener 등록
setFragmentResultListener("requestKey") { requestKey, bundle ->
//결과 값을 받는곳입니다.
val result = bundle.getString("bundleKey")}
- 프래그먼트 B에서 프래그먼트 A로 데이터를 다시 전달하려면 우선, 결과를 수신하는 프래그먼트인 프래그먼트 A에서 결과 리스너를 설정한다.
- 다음 예와 같이 프래그먼트 A의
FragmentManager
에서setFragmentResultListener()
를 호출한다.
- 다음 예와 같이 프래그먼트 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를 지정해 줘야한다.