[팀 프로젝트] Yu Market 첫번째 코드 리뷰 2편 (2)

쓰리원·2022년 2월 3일
0

TeamProject_Yu Market

목록 보기
2/5
post-thumbnail

1. 코드 리뷰를 통해 무엇을 공부하고 배웠는지 같이 알아보겠습니다.


박카스팀 첫번째 코드 리뷰를 발표를 진행한 치타개발자 팀원의 velog 입니다.

https://velog.io/@18k7102dy/team-projectcode-review1


DiffUtil.ItemCallback 분석하기

1. 코드 분석하기

abstract class BaseModel(
    open val id : Long,
    open val type : CellType
) {

    open fun isTheSame(item: BaseModel) : Boolean {
        return this.id == item.id && this.type == item.type
    }

    companion object {
        val DIFF_CALLBACK = object: DiffUtil.ItemCallback<BaseModel>() {
            override fun areItemsTheSame(oldItem: BaseModel, newItem: BaseModel): Boolean {
                return oldItem.isTheSame(newItem)
            }

            @SuppressLint("DiffUtilEquals")
            override fun areContentsTheSame(oldItem: BaseModel, newItem: BaseModel): Boolean {
                return oldItem == newItem
            }
        }
    }
}

위 코드에서 과거(oldItem)와 현재(newItem) 리스트의 차이를 비교 해서 areItemsTheSame과 areContentsTheSame를 override 해주는 것을 확인 할 수 있습니다.

아래의 그림으로 각 함수의 사용을 설명하겠습니다.

    open fun isTheSame(item: BaseModel) : Boolean {
        return this.id == item.id && this.type == item.type
    }
    
    override fun areItemsTheSame(oldItem: BaseModel, newItem: BaseModel): Boolean {
                return oldItem.isTheSame(newItem)
    }
            

areItemsTheSame은 위와 같이 id 값과 같은 고유값을 비교해서 같은 id인지 확인을 합니다. 이를 통해 이전 항목과 같은 것 인지 테스트를 하게 됩니다. 같으면 true를, 아니면 false를 리턴합니다.

여기서 areItemsTheSame에 false가 나오게되면 false가 나온 항목의 viewholder 를 다시 그려주게 됩니다. 그래서 깜빡거리는 현상이 나타나게 됩니다. true를 반환시에는 깜빡거리는 현상이 나타나지 않습니다.

false 의 경우 예시)

위의 예시는 전체가 깜빡이지만, areItemsTheSame은 항목 id 각각을 비교하여 flase를 반환한 경우 일치하지 않는 id만 viewholder부터 다시 그리고 안의 내용이 작성되게 됩니다. 그래서 true를 반환하는 id의 경우는 깜빡거리지 않습니다.

    @SuppressLint("DiffUtilEquals")
    override fun areContentsTheSame(oldItem: BaseModel, newItem: BaseModel): Boolean {
        return oldItem == newItem
    }

areContentsTheSame 은 areItemsTheSame true일 경우만 호출이 됩니다. 그래서 true가 반환이 된다면 viewholder는 다시 그리지 않기 때문에 깜빡거리는 것이 없게 data class 내부의 값 전체를 다 비교합니다. 비교 후 바뀐 Contents 값을 갱신 해줍니다.

true 의 경우 예시)

2. Yu Maket의 경우 어떻게 적용 되었나.

테스트 mock data 2개의 List를 각각 준비합니다.

    override fun getAllMarketList(): List<TownMarketModel> {
        val mockList = listOf(
            TownMarketModel(
                id = 0, "쥬얼리 샵", true,
                LocationLatLngEntity(128.0, 36.0),
                "https://picsum.photos/200", 0.11f
            ),
            TownMarketModel(
                id = 1, "옷가게", true,
                LocationLatLngEntity(128.0, 36.0),
                "https://picsum.photos/200", 0.22f
            ),
            TownMarketModel(
                id = 2, "피자스쿨", true,
                LocationLatLngEntity(128.0, 36.0),
                "https://picsum.photos/200", 0.33f
            ),
            TownMarketModel(
                id = 3, "빅마트", false,
                LocationLatLngEntity(128.0, 36.0),
                "https://picsum.photos/200", 0.44f
            ),
            TownMarketModel(
                id = 4, "롯데리아", false,
                LocationLatLngEntity(128.0, 36.0),
                "https://picsum.photos/200", 0.10f
            )
        )

        return mockList
    }
override fun getAllMarketListtest(): List<TownMarketModel> {
        val mockList = listOf(
            TownMarketModel(
                id = 0, "쥬얼리 샵", true,
                LocationLatLngEntity(128.0, 36.0),
                "https://picsum.photos/200", 0.11f
            ),
            TownMarketModel(
                id = 1, "옷가게", true,
                LocationLatLngEntity(128.0, 36.0),
                "https://picsum.photos/200", 0.22f
            ),
            TownMarketModel(
                id = 2, "피자스쿨(test)", true,
                LocationLatLngEntity(128.0, 36.0),
                "https://picsum.photos/200", 0.33f
            ),
            TownMarketModel(
                id = 5, "빅마트(test)", false,
                LocationLatLngEntity(128.0, 36.0),
                "https://picsum.photos/200", 0.44f
            ),
            TownMarketModel(
                id = 4, "롯데리아(test)", false,
                LocationLatLngEntity(128.0, 36.0),
                "https://picsum.photos/200", 0.10f
            )
        )

        return mockList
    }

각 데이터들은 실험을 위해서 서로의 차이를 둬서(test)를 붙였습니다. 빅마트의 경우만 id 값이 3->5로 변경되었고 나머지는 id값의 변경이 없습니다. 옷가게와 쥬얼리 샵은 test를 붙이지 않아서 데이터의 변경이 일어나지 않게 하였습니다.

위와 같이 데이터 값을 정해놓고 areContentsTheSame 과 areItemsTheSame 을 어떻게 이해하고 사용하였는지 확인 해보겠습니다.

id값의 변환이 있기 때문에 뷰홀더를 다시 그려서 빅마트의 경우만 크게 깜빡거리는 것을 확인할 수 있습니다. areContentsTheSame에서 false를 반환했기 때문이죠. 나머지 경우 피자스쿨의 경우 살짝 반짝이는 경우를 알 수 있는데 제목이 test가 붙어서 변했기 때문에 뷰홀더를 다시 그리지는 않고 내부의 데이터값만 변환 되는 것을 알 수 있습니다.

3. Outro

이렇게 해서 Diffutil.ItemCallback 에 대해서 팀원들은 정확하게 이해할 수 있게 되었습니다. 피상적으로 코드로만 이해할 것이 아니라 test를 하여서 더 정확하고 깊게 이해할 수 있었습니다.

DiffUtil.ItemCallback에 대한 심층적인 분석을 이로써 마치겠습니다. 도움이 되셨으면 좋겠습니다.

2편은 여기서 마치고 3편 Koin DI에 관해 다음 글을 작성하겠습니다.


4. reference :

https://developer.android.com/reference/androidx/recyclerview/widget/DiffUtil.ItemCallback
https://ichi.pro/ko/listadaptere-jeog-eung-57301912358747
https://thdev.tech/kotlin/2020/09/22/kotlin_effective_03/

profile
가장 아름다운 정답은 서로의 협업안에 있다.

0개의 댓글