[TIL] RecyclerView: List Adapter

박봉팔·2024년 1월 17일
0

RecyclerView.Adapter

리사이클러뷰는 사용하려면 어댑터를 연결해줘야 하는데, 이때 RecyclerView에 있는 Adapter(리사이클러뷰 어댑터)를 연결해서 사용하면 데이터가 변경될때마다 리사이클러 뷰를 사용하기 위해 다시 notify해줘야하는 번거로움이 있다.

또 보다 효율적인 작동을 위해서는 모든 데이터를 다시 그리는 notifyDataSetChanged()를 사용하기보다는 해당 데이터의 포지션을 구해 변경된 데이터만 다시 notify해주는게 좋은데, 이때 포지션의 값을 구하는게 굉장히 까다롭다.


List Adapter

리사이클러뷰 어댑터의 번거로움을 해결하기위해 diff util을 사용하는데 List Adapter의 경우 이 diff util을 매개변수로 받아 스스로 업데이트 할 수 있도록 해주는 어댑터이다.


diff util

객체로 선언해 List Adapter에 전달할 경우 기존의 아이템과 변경된 아이템을 비교해 변경된 부분을 자동으로 notify해주는 기능을 가지고 있다.

companion object {
	val diffUtil = object : DiffUtil.ItemCallback<ContactItems>() {
    	override fun areItemsTheSame(oldItem: ContactItems, newItem: ContactItems): Boolean {
                return oldItem.ItemID == newItem.ItemID
		}

        override fun areContentsTheSame(oldItem: ContactItems, newItem: ContactItems): Boolean {
        	return oldItem == newItem
		}
	}
}

기본적으로 diff Util은 2가지의 함수를 override해서 사용하는데 각 함수는 다음과 같은 역할을 한다.


areItemsTheSame() 함수에서는 기존의 oldItem과 변경된 newItem이 같은 아이템인가를 비교한다.
보다 효율적인 동작을 위해서는 oldItemnewItem을 직접비교하는 것보다. 아이템이 가지고 있는 고유한 프로퍼티를 비교하는 것이 좋다.

areItemsTheSame()의 경우 아이템이 서로 같은 아이템인가를 비교하는 함수기 때문에 아이템 내용이 변경된 부분에 대해서는 비교하지 않는다.


areItemsTheSame()에서 oldItemnewItem이 같을 경우 artContentsTheSame()함수 에서 해당 아이템의 모든 프로퍼티를 비교한다.
해당 프로퍼티를 비교해 변경된 부분이 있을 경우 리사이클러 뷰에서 해당 아이템의 뷰홀더를 새로 그리도록 한다.


주의사항: 오늘의 이슈

초기에 리사이클러뷰에 어댑터를 세팅할때 List Adapter에 데이터 리스트를 그대로 전달했다.

데이터 리스트를 전달하면서 얕은 복사가 실행되었지만, 리스트 내부의 값들은 각각 Data Class로 이루어져있어 결과적으로 어댑터 내부의 데이터 리스트와 Single Tone으로 저장되어있는 데이터 리스트가 같은 데이터를 공유하고 있었다.

그렇기 때문에 데이터 리스트의 크기가 변경될 경우에는 (데이터가 추가/삭제될 경우) diff util에서 변화를 인식해 데이터를 새로 그리는 반면, 리스트 내부의 Data Class의 프로퍼티값을 변경할 경우에는 서로 바라보는 값이 같아 변경된 부분이 없다고 인식되어 실제로는 데이터가 변경되었음에도 불구하고 새로 그려지지 않는 경우가 발생했다.


- 트러블 슈팅

문제 해결을 위해 diff util의 각 함수에 Break Point를 찍어 확인해 보았고, 값이 변경 될 때
oldItemnewItem이 모두 변경되는 것을 확인했다.

그래서 Single Tone 데이터 리스트에서 List Adapter에 데이터를 전달할 때
새로운 리스트를 생성해 각 Data Class들을 .copy()를 하여 기존과는 다른 Data Class를 가지고 있는 데이터 리스트를 전달하도록 했다.

그리하여 oldItemnewItem이 같은 데이터를 바라보는 것을 방지하였고, 그 결과 submitList()를 통해 새로운 데이터를 전달할 경우에 정상적으로 diff util이 작동하는것을 확인하였다.


오늘은 어땠나요?

드디어 어제부터 문제 있던 부분을 해결했는데,

왜 때문에 또 이해할게 산더미인거죠?

산 넘어 산입니다 아주...

profile
개발 첫걸음! 가보자구!

0개의 댓글