들어가기 전
엄빠도 어렸다 서비스를 만들면서 두 사용자가 7일차까지 모두 답변을 마쳤을 때 홈화면 대신 엔딩화면이 팝업처럼 띄워지도록 구현해야했다. registerForActivityResult를 통해서 이 기능을 구현한 과정과 겪은 트러블슈팅을 포스팅해보도록 하겠다.
registerForActivityResult 란?
기존의 Activity간의 이동을 할 때 startActivity(intent : Intent )를 통해서 단방향 이동을 하고, 데이터값 전달과 함께 양방향 이동을 위해서는 startActivityForResult(intent:Intent, requestCode:Int) 을 사용했다.
하지만 startActivityForeResult는 콜백 수행의 안정성, 보일러플레이트 코드의 증가 이슈로 인해 현재는 Deprecated 되었다. 그리고 이를 대체하기 위해서 activity result에 callback을 등록하는 registerForActivityResult를 사용하게 되었다.
registerForActivityResult 사용방법
A activity와 B activity 간에 데이터를 주고받는다고 상황을 가정해보자.
A activity 코드
A activity에서는 registerForActivityResult 함수를 사용해 Callback 을 등록한다.
이 때 매개변수로 StartActivityForResult()가 들어간다.
콜백에서는 result로 받아온 값을 이용하면 되는데, 받아온 result를 통해서 resultCode와 data에 접근할 수 있다.
B activity에서 받아온 resultCode가 RESULT_OK라면 B activity에서 온 data를 접근해 가져올 수 있다.
이렇게 정의한 callback을 launch 함수로 intent를 넣어주면 A activity에서 B activity로 이동할 수 있다.
B activity에서 데이터 보내기
B activity에서는 a→b로 왔기 때문에 데이터를 실어 다시 A activity로 보내주면 된다.
이 때 setResult 함수로 resultCode와 intent(data를 실은)를 실어서 현재 activity를 finish() 해주면 A activity로 돌아가 콜백 함수의 RESULT_OK 조건문으로 들어가게 된다.
위 코드에서는 따로 data를 실지 않았지만 data를 실을 경우 아래와 같이 코드를 작성하면 된다.
팝업 창 같은 엔딩 Activity 만들기
나는 위 같은 registerForActivityResult를 이용해서 엔딩페이지를 만들었다.
엔딩페이지를 만들 때 고려해야 할 사항은 아래 2가지였다.
- 두사람 모두가 답변했을 경우만 엔딩페이지를 보여주기
- 사용자가 엔딩페이지 x를 눌렀으면 홈에 머무르는 동안 엔딩페이지가 안뜨도록 하기
첫번째 조건은 서버에서 보내주는 index 값을 통해서 처리할 수 있었지만, 두번째 조건은 사용자가 엔딩페이지 x 버튼을 눌렀는지에 대한 값을 갖고 있어야 했다.
이를 처리하기위해서 home→ ending 후 ending→home으로 돌아오면 무조건 x를 누른 상황이므로 이 때 registerForAcitivtyResult를 사용하였다.
home viewModel에 ending page x값을 누른 정보 값을 갖는 변수를 선언했고, fragment가 처음 그려질 경우는 ending page x 값을 누르지 않았기에 초기값을 false로 선언하였다.
그 후 registerForActivityResult 콜백에 resultCode 가 RESULT_OK일 경우 엔딩에서 홈으로 X버튼을 눌러 들어온 조건이므로 x값을 누른 정보 값을 true로 변경해주는 작업을 진행하였다.
이렇게되면 home에서 이미 사용자가 엔딩페이지 x를 눌렀음을 알기 때문에 홈 내에서 또 엔딩페이지를 띄우지 않을 수 있다.
엔딩페이지가 두 번 뜨는 트러블슈팅 발생
위같이 처리했을 때 home→ending은 조건에 맞게 잘 뜨나 x버튼을 한번 눌렀을 때 엔딩페이지가 또 생성되고 한번 더 눌러야지만 finish()가 되는 문제가 발생하였다.
문제를 분석해보니 ending activity가 두 번 생성되는 것이였다.
원인은 바로 생명주기를 제대로 고려하지 않아서 였는데..
생명주기의 중요성 깨닫기
fragment는 처음에 onCreate()→ onViewCreated() 를 거쳐 뷰가 생성되고 onResume() 상태에 도달해 사용자와 상호작용이 적절히 가능한 상태임을 나타낸다.
나는 onResume() 상태가 pause 되고 다시 되돌아 왔을 때만 실행되는 함수라고 착각한 것이다. 따라서 ending page로 가는 함수를 onResume()에도 호출시켜 두번의 엔딩페이지가 뜨는 문제가 발생했다.
간략하게 문제를 설명하였지만, 두 사용자가 답변을 모두 한 것이 아닌 한 사람만 답변을 한 경우에는 답변하기 버튼을 눌러 답변화면에서 답변 후 onResume()로 다시 home에 돌아오면 엔딩페이지가 떠야했기 때문에 onResume()에도 엔딩페이지를 불러오는 함수를 작성한 것이였다.
트러블 슈팅 해결
따라서 현재 초반에 index를 확인했는지 안했는지를 판단하는 변수를 하나 만들어
view가 생성되면서 observe 했다면 그 값을 true로 만들고, onResume()에서는 다시 호출하지 않도록 코드를 짰다.
마치며
이 코드를 작성하면서 view에 로직이 너무 많이 들어간 것은 아닌가? 라는 걱정이 들었다. 요즘 view와 viewModel에 역할을 분리하고, 최대한 view에는 UI를 그리는 코드만 들어가도록 노력하고 있는데 이게 참 쉽지않은 것 같다.
현재는 릴리즈를 위해서 바쁘게 코드를 짜느라 많이는 고려하지 못했다. 하지만 리팩토링 과정에서 유지보수에 좋은 코드를 위해 최대한 레이어를 분리하고, 각 레이어가 최소한의 역할만 수행하도록 하는 코드를 짜도록 노력해야겠다.
자세한 코드는 아래 레포를 참고해주세요.
https://github.com/Team-Umbba/Umbba-Android
GitHub - Team-Umbba/Umbba-Android: 누가 이렇게 예쁘게 낳았어? 우리 엄빠엄빠가~ 엄빠엄빠가~ ♬
누가 이렇게 예쁘게 낳았어? 우리 엄빠엄빠가~ 엄빠엄빠가~ ♬. Contribute to Team-Umbba/Umbba-Android development by creating an account on GitHub.
github.com
'Android > 프로젝트 개발' 카테고리의 다른 글
[Android] Retrofit에서 XML 데이터 통신 및 파싱 방법 / RecyclerView XML 데이터 받아오기 (0) | 2024.02.26 |
---|---|
[Android] 인앱 업데이트 구현하기 / 인앱 업데이트 테스트 (1) | 2023.11.01 |
[Android] 안드로이드 MaskFilter로 blur 효과 구현하기 (0) | 2023.08.07 |
[SWith] 검색 무한스크롤 (0) | 2022.09.24 |