Uing? Uing!!

[안드로이드 삽질기록] java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling androidx.recyclerview.widget.RecyclerView 본문

Android

[안드로이드 삽질기록] java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling androidx.recyclerview.widget.RecyclerView

Uing!! 2021. 7. 16. 01:52
반응형

발단

액티비티 내에 RecyclerView가 있었고, 스크롤 관련된 로직이 많았다.

그런데 특정 상황에서 이 글의 제목과 같이,

java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling androidx.recyclerview.widget.RecyclerView

라는 크래시로그가 나는 것을 발견했다. OMG.

해당 크래시가 발생하는 위치는 notifyItemInserted였다.

삽질

스택트레이스 메시지를 보고 당연히 스크롤과 관련된 문제일거라고 생각했다.

구글링을 해 보아도 stackOverflow에서는 notifyItem~ 메소드가 스크롤 이후에 실행될 수 있도록 post{}하라는 의견이 많았다.

하지만 notify 메소드를 쓰는 위치가 한두 군데가 아니어서 일일이 처리하기가 난감하기도 했고, post를 통해 임시방편으로 문제가 발생하지 않도록 막는 것이 찝찝하기도 했다.

 

그래서 근본적인 문제가 무엇일지에 대해 조금 더 생각했다.

결국 알아낸 사실은, 에러 메시지의 '... computing a layout or scrolling ...' 중에서 문제가 되는 부분은 'scrolling'이 아닌 'computing layout'이라는 것이었다.

(에러 문구를 다시금 읽어 보아도, 이 stackTrace 메시지를 가지고 해법을 바로 찾기가 용이하지는 않은 것 같다. 이렇게 적어 놓으면 대부분 스크롤 문제라고 생각하게 되지 않나...?)

 

이 문제가 발생한 원인은 리사이클러뷰 어댑터에 있었다.

onBind는 최소한의 역할만 하는 것이 좋은데, 기능 상 onBind가 너무 비대해져서 놓친 코드가 있었던 것이다.

 

이 어댑터는 onCreate에서 textChangedListener를 추가하는데, 특정 상황에서 notifyItemInserted를 호출하게 되어 있었다.

그런데 onBind에서 setText로 아이템뷰에 텍스트가 설정되면, onCreate에서 연결해 둔 onTextChanged가 호출되었고, 위의 '특정 상황'이 발동해서 notifyItemInserted가 호출된 것이다.

즉, 결과적으로 onBindViewHolder 내부에서 notify~가 호출되고 있어 생기는 에러였다.

결론

notifyItemInserted가 onBindViewHolder내부에서 호출되는 일이 없도록 코드를 수정하니 같은 상황에서도 더이상 크래시가 발생하지 않았다.

 

이후에도 onBind에서 notify가 불리지 않도록 주의하고,

또 놓치는 코드가 생길 수 있으므로 onCreate, onBind가 너무 비대해지는 것은 유의해야 할 듯하다.

반응형
Comments