1. 사건 배경
2. 증상
3. 시도한 방법
3-1. LifeCyclerOwner 확인
3-2. 액티비티 수명 상태 확인
3-3. observerForever 사용
3-4. hasActiveObservers 사용
4. 결론
어쩐지 검색해도 해결방법이 안 나오더라니 이런 멍청한 실수를 하는 건 나밖에 없는 것 같아서 이 포스팅을 쓸까 말까 고민했다. 그치만 삽질하면서 배운 것도 있고, 만약 한 분이라도 이 글을 보고 문제를 해결하면 내가 그 분의 시간을 아껴드리는 거니까! 적어보기로 했다.
1. 사건 배경
Retrofit에 대한 정리 글을 올릴 때 글을 보시는 분들이 LiveData에 대해 모르고 계시면 헷갈릴까 봐 콜백 함수를 써서 예제를 만들었었다. 그리고 LiveData 예제를 만드는데 새로 만들기 귀찮아서 (이게 이번 일의 원흉이 됐다 👿) 기존 예제를 고쳐 쓰다가 이 사태가 벌어졌다.
2. 증상
LiveData를 관찰하는 Observer가 최초 딱 1번만 관찰을 하고 그 뒤로는 관찰을 하지 않았다.
관찰을 안할거면 아예 안 하던가 할 거면 끝까지 하던가 1번만 작동하다니 내 머리로는 이해가 가지 않았다.
3. 시도한 방법
3-1. LifeCyclerOwner 확인
model.getAll().observe(this, Observer{
noticeAdapter.setList(it.content)
noticeAdapter.notifyDataSetChanged()
})
observer에게 넘겨주는 this는 LifeCyclerOwner 값이다.
즉, 관찰자가 누구의 수명주기를 따를 것이냐를 뜻한다.
호오오옥시나 액티비티 말고 다른 수명주기를 따르고 있나 해서 확인해봤는데 this가 액티비티를 잘 가리키고 있었다.
(this를 컨트롤 + 클릭 하면 된다)
만약 프래그먼트에서 Observer를 생성하는데 this를 사용하고 있다면 잘못된 방법이다.
this 대신 viewLifeCyclerOwner를 사용해야 하며 자세한 내용은 Pluu Dev님 블로그에서 확인할 수 있다.
3-2. 액티비티 수명 상태 확인
그 다음에 확인한 건 호오오오옥시나 액티비티가 Destroy 되나?? 였다.
공식문서에 따르면 액티비티의 수명주기가 끝나는 즉시 수신이 거부된다고 써있었기 때문이다.
내 눈앞에 멀쩡하게 액티비티가 살아있지만 그래도 확인해봤다. 하지만 역시 그럴리는 없었다.
액티비티의 수명주기와 관련 없는 증상임을 알아냈다.
3-3. observerForever 사용
model.getAll().observeForever( Observer{
noticeAdapter.setList(it.content)
noticeAdapter.notifyDataSetChanged()
})
이번에는 observerForever를 사용해봤다.
이것도 공식문서에서 본건데 observerForever를 사용하면 수명주기가 연결되지 않아도 관찰자로 등록할 수 있고
항상 활성상태로 간주되어 항상 알림을 받는다고 한다.
(대신 관찰자를 삭제하려면 removeObserver를 호출해야 함)
아무튼! 항상 알림을 받는다고 했으니 이걸 사용하면 최초 1회만 알림을 수신하는 이 문제를 해결할 수 있을 것 같았다.
(근본적인 해결 방법은 아니지만)
하지만 이 방법도 먹히지 않았다. 뭔가 쎄- 한 것이 엉뚱한 곳에서 어이없는 실수를 하고 있다는 느낌이 들었다.
3-4. hasActiveObservers 사용
더 자세히 원인을 찾기 위해 Observer의 state를 확인할 수 있는 메서드를 공식문서에서 찾아보았다.
hasActiveObservers 라는 메서드가 있는데 현재 활성화된 Observer가 있는지 boolean으로 리턴해주는 메서드이다.
바로 확인에 들어갔는데 최초 실행시에 True이던 값이 두 번째 실행부터 False로 바뀌는 걸 확인했다.
4. 결론
이후에도 이래저래 삽질하다 알아낸 결론은..
우선 [목차 1]에서도 말했듯이 나는 콜백 함수를 사용하는 예제를 재활용했다.
액티비티에서 Repository로 값을 요청하고, 콜백 함수를 통해 액티비티에게 응답했다.
예제를 수정하면서 콜백함수 부분을 지웠는데
버튼을 누르면 요청하는 부분(빨간색 요청)을 파란색 요청으로 바꾸는 걸 까먹고 그대로 두었다.
액티비티가 실행되면 처음에 보여줄 데이터를 요청하는 건 파란색 요청으로 잘해놓고서
버튼을 누르면 요청하는 걸 빨간색 요청으로 안 고치고 둔 것이다.
즉, 처음 실행 때는 파란색 요청을 하고 파란색 응답을 받으니 잘 되는구나 했는데
버튼을 누르면 빨간색 요청만 하니까 응답이 안 오지... Repository 객체가 다르니까 🤦🏻♂️
이런 멍청한 짓을 하는 사람이 세상에 어디 있냐구요?
아무튼 혹시나 나와 상황을 겪은 사람이 있다면
내가 원인을 찾아나가면서 사용한 방법이 도움이 될까 해서 글을 적었다.
해외 커뮤니티에도 비슷한 질문 글을 올라온 걸 찾았는데 이 사람은 LiveData에 값을 넣을 때 value 말고 postValue를 사용하는 거로 해결한 듯하다. 자세한 내용은 이거랑 이거!
💡 느낀 점
- 평소 LiveData 공식문서를 읽어놨던 것이 문제 해결에 도움이 됐다.
- LiveData를 사용할 줄만 알고 수명 상태나 잘 안 쓰이는 메서드의 존재를 몰랐다면 문제 해결 접근이 더 어려웠을 듯
- 아무튼 난 멍청이다. 이런 실수를 하다니.
📘 참고한 자료
'오늘은 뭘 배울까? > 삽질 기록' 카테고리의 다른 글
결제 구현 중 productDetailsList가 empty list를 받아오는 이유 (3) | 2023.11.02 |
---|---|
stateflow가 같은 값을 update 하는 이유 (0) | 2023.01.26 |
GitHub 토큰 인증 로그인 : support for password authentication was removed (2) | 2021.08.21 |
recyclerView를 업데이트 하는 5가지 방법 (notifyDataSetChanged를 사용하지 말자) (14) | 2021.06.18 |
댓글