본문 바로가기
오늘은 뭘 배울까?/삽질 기록

Observer가 LiveData를 관찰 못할 때

by Kim Juhwan 2021. 5. 5.

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로 값을 요청하고, 콜백 함수를 통해 액티비티에게 응답했다.

 

 

LIveData를 이용한 예 (+ 멍청한 짓)

예제를 수정하면서 콜백함수 부분을 지웠는데

버튼을 누르면 요청하는 부분(빨간색 요청)을 파란색 요청으로 바꾸는 걸 까먹고 그대로 두었다.

액티비티가 실행되면 처음에 보여줄 데이터를 요청하는 건 파란색 요청으로 잘해놓고서

버튼을 누르면 요청하는 걸 빨간색 요청으로 안 고치고 둔 것이다.

 

즉, 처음 실행 때는 파란색 요청을 하고 파란색 응답을 받으니 잘 되는구나 했는데

버튼을 누르면 빨간색 요청만 하니까 응답이 안 오지... Repository 객체가 다르니까 🤦🏻‍♂️

 

이런 멍청한 짓을 하는 사람이 세상에 어디 있냐구요?

 

멍청한 사람 바로 나야나

 

아무튼 혹시나 나와 상황을 겪은 사람이 있다면

내가 원인을 찾아나가면서 사용한 방법이 도움이 될까 해서 글을 적었다.

해외 커뮤니티에도 비슷한 질문 글을 올라온 걸 찾았는데 이 사람은 LiveData에 값을 넣을 때 value 말고 postValue를 사용하는 거로 해결한 듯하다. 자세한 내용은 이거이거!

 

 


💡 느낀 점

  • 평소 LiveData 공식문서를 읽어놨던 것이 문제 해결에 도움이 됐다.
  • LiveData를 사용할 줄만 알고 수명 상태나 잘 안 쓰이는 메서드의 존재를 몰랐다면 문제 해결 접근이 더 어려웠을 듯
  • 아무튼 난 멍청이다. 이런 실수를 하다니.

📘 참고한 자료


반응형

댓글