안드로이드 어플리케이션은 컴포넌트로 구성된다. ActivityManager는 이름과 달리 (액티비티 사이가 아닌) 컴포넌트들 사이에 Intent 형태의 데이터를 주고 받을 수 있게 해준다. 특히, 액티비티 간 데이터를 주고 받을 때 용이하도록 액티비티는 startActivity(), startActivityForResult(), onActivityResult() 메소드를 제공한다. 이 메소드들은 프레그먼트에도 있는데, 여기서는 프레그먼트의 onActivityResult()에 대해 살펴보자.
결론부터 말하면, 프레그먼트의 onActivityResult()도 다른 액티비티에서 데이터를 받을 수 있다. 다른 특별한 처리 없이 말이다.
지금 인터넷을 보면 액티비티의 onActivityResult()만 다른 액티비티나 프레그먼트에서 startActivityForResult() 통해 요청한 작업의 결과를 받을 수 있다고 한다. 그리고, 프레그먼트의 onActivityResult()에 데이터를 전달하는 다양한 방법들(FragmentManager를 통한 프레그먼트의 onActivityResult() 명시적 호출, 이벤트 버스 사용 등)을 소개한다. 글의 말미에 안드로이드가 이상하게 동작한다는 불만도 잊지 않는다.
아마도 이런 오해는 어떤 메소드를 호출하느냐에 따라 액티비티 간 데이터 전달 동작이 다르다는 것을 몰라 생긴 것 같다. 데이터를 주고 받는 규칙을 살펴보자.
- 액티비티의 onActivityResult()는 액티비티나 프레그먼트 둘 중 어느 것의 결과든 받는다.
- 프레그먼트의 onActivityResult()는 프레그먼트의 startActivityForResult()를 통해 호출한 액티비티에서만 결과를 받는다.
- 프레그먼트는 액티비티의 onActivityResult()가 호출 된 후 호출 된다. 정확히, 프레그먼트의 onActivityResult()는 액티비티의 onActivityResult() 코드 내부에서 호출된다.
그러므로, 아래와 같이 사용하면 결과를 받을 수 없다.
- 프레그먼트 안에서 (예를 들면, getActivity() 같은 메소드를 통해 얻은) 액티비티 객체의 startActivityForResult()를 호출한다. 이 때는, 액티비티의 startActivityForResult()를 호출한 것이므로 액티비티로만 결과가 전달된다.
- 내 액티비티에서 onActivityResult() 메소드를 오버라이드 한 후, 이 메소드에서 super.onActicityResult()로 결과를 전달하지 않고 전달받은 결과 데이터를 소진한다. 프레그먼트는 데이터를 액티비티의 onActivityResult()를 통해 전달받기 때문에 super.onActivityResult()로 값을 전달하지 않으면 프레그먼트에도 전달되지 않는다.
즉, 아래와 같이 해야 프레그먼트에서 호출 후 결과를 받을 수 있다.
- Activity.startActivityForResult()가 아닌Fragment.startActivityForResult()를 사용해 호출한다.
프레그먼트 속 onActivityResult()가 기대대로 동작하지 않아 힘들었다면, 지금이라도 바르게 사용해 보자.
그 밖에
- 사실 액티비티에서 프레그먼트에 결과를 전달하는 과정은 인터넷에 알려진 FragmentManager를 이용한 자식 프레그먼트들의 onActivityResult() 명시적 호출과 크게 다르지 않다.
- 프레그먼트를 추가할 때 건넨 tag를 이용해 프레그먼트를 찾기라도 한다면, 이 태그를 통해 액티비티와 프레그먼트가 강결합하게 되어 더 나쁘다.
- 액티비티-프레그먼트A-프레그먼트B 순으로 포함하는 계층 구조라도, 프레그먼트 B에서 호출한 액티비티의 결과를 프레그먼트 A가 받지는 않는다. 액티비티에서 각 프레그먼트에 결과 값을 전달한다.
- Fragment의 공식 문서를 보면 프레그먼트의 onActivityResult()에 대한 설명이 단촐하다. ‘액티비티의 onActivityResult()와 관련이 있다.’는 언급이 있을 뿐이다.
- 액티비티의 onActivityResult()는 스코프(scope)가 protected이고, 프래그먼트의 그 것은 public이다. 액티비티에서 호출하기 위한 목적일 것이다.
참조
멋진 설명입니다.
감사합니다 🙂
핑백: FragmentManager와 ChildFragmentManager – Dog발자
와 먼말인가여
그림같은 것으로 좀 더 친절하게 설명했어야 하는데, 제 생각을 정리해 두는 수준으로 적다보니 어려운 글이 되어버렸나 봅니다. 다음에 그림 추가해 볼께요.
참나 결국엔 못사용한다는거아님? 낚였네 뭐하는거지진짜 ㅡㅡ 짜증지대로난다
다시 한번 잘 읽어보시면, 안드로이드에서 지원하는 대로 쓰면 따로 커스텀하지 않아도 된다는 글입니다.
이해를 못했으면 이해를 못했다고 작성자분께 정중히 여쭤보시길..
내용은 전혀 문제가 없고 좋은 내용인데 자신의 무지를 탓하세요
뭐라는거야 제목은 받기라고해놓고선 결국엔 못받는다는거잖아 장난?
댓글 입력도 안되네 뭐냐진짜 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ
설명 감사합니다. 고민하던부분이 일부해결되었네요. 추가로 질문드리자면 프레그먼트에서 호출할때 Fragment.startActivityForResult() 로선언한다면 프레그먼트가 속해있는 부모 액티비티에 별도의 코드없이 프레그먼트 내부의 onActivityResult()에서 받는다는것이 맞는지요??
네. 맞습니다.
FragmentManager 를 사용하거나 Custom Event Class 를 사용한다는 다른 글과 다른 유용한 글이네요.
몇몇 댓글들이 글을 망치고 있는게 아쉬워서 댓글 남겨요
알아주셔서 감사합니다.
전 굉장히 많이 도움이 되는 글이네요. 안에 동작이 잘 이해돼서 알아서 문제 해결할 수 있을 것 같아요. 다른 댓글이 아쉬워서 응원차 댓글 남겨요.
응원 감사합니다.
현재 글은 더 다듬었습니다. 처음에는 이해하기 어려운 부분이 있었던 것 같아요 🙂
ㅋㅋㅋ 왠만하면 댓글 안다는데 징징거리는 사람들때문에 스트레스 받지마세영
네, 감사합니다 🙂 다들 이해가 잘 안되나보더라고요. 그림이라도 그려서 더 쉽게 설명하면 좋을텐데, 마음이 안내키네요. 창이 님도 즐거운 추석 되세요.
감사합니다! 완전 도움되는글인데 저렇게 댓글다는거보면 어이가없네요 ㅋㅋ.
요지는 된다 안된다가 아니라 되는데 굳이 커스텀할필요없이 프래그먼트에서 제공해주는대로 사용하라인데 참… ㅋㅋ
댓글들 보고 글을 많이 개선했습니다 🙂
당시엔 가독성이 안좋았나봐요.