본문 바로가기

Android/Trouble Shoot

[Jetpack Compose] List 아이템의 필드 변경이 Recomposition 을 트리거 해야 할 때

Unsplash, David wirzba.

어떤 이슈가 있었나?

List 내 원소의 필드를 직접 수정하여 UI 를 업데이트 하려 하였으나, 생각하는 대로 되지 않았습니다.

당연히, 해당 List의 객체가 이전의 객체와 같으므로 UI 업데이트가 진행되지 않았으리라 판단하고, 해당 List에 대해 toMutableList() 메서드를 사용하여 새로운 객체로 반환했습니다. RecyclerView 와 RecyclerView.Adapter 를 사용할 때에 이러한 문제를 해결할 수 있었으니까요.

 

 

분명히 List 객체도 변경해주었고 State 객체를 업데이트 해주었음에도 불구하고, UI 가 업데이트되지 않고 있습니다.

 


어떻게 해결하였나?

List의 toMutableList() 메서드는 List를 새로운 객체로 반환하지만, List 아이템의 객체들까지 새로운 객체로 변경되지는 않습니다. Composable 이 참조하고 있는 것은 List 객체가 아니라 List 아이템 객체이므로, List 아이템이 새로운 객체로 바뀌어야만 합니다. 

 

단순히 List 아이템 객체의 필드를 바꾸고 List를 toMutableList() 하여 내보내는 방식이 의도한 대로 작동하지 않았던 이유는, List 아이템 객체가 원본 객체와 같은 객체이기 때문입니다. 

 

해결을 위해서는 List 아이템 객체를 바꿔주어야 하므로, Collection 확장함수를 사용하여 바꾸어 줄 수 있겠습니다. 코틀린에서 기본적으로 제공하는 Collection 의 확장함수들은 대체로 새로운 List 객체를 반환합니다. 그 중, 모든 항목에 대한 매핑이 이루어지는 map {} 확장함수를 사용하고, data class 의 copy() 메서드를 사용하여 해결할 수 있었습니다.

 

_state.update {
    it.copy(reviewList = sortRefreshedReviewList(state.value.reviewList.map { review ->
        if (review.id == reviewId) {
            review.copy(liked = false, likeCount = review.likeCount?.minus(1))
        } else {
            review
        }
    }))
}

 

위와 같이 코드를 작성하면, 조건에 해당하는 원소가 깊은 복사를 통해 새로운 객체로 대체되어 UI가 업데이트될 수 있습니다.

 

 

이는 Composable 의 수명주기와 관련이 있는 이슈입니다.

Composable 의 수명주기는 Initial Composition 을 통한 Composition 의 시작과 0회 이상의 Recomposition, Composition 종료로 이루어집니다.

 

Recomposition 은 해당 Composable 이 참조하고 있는 State 가 변경될 때 발생하는데, 해당 이슈의 경우 liked 변수가 State 로 래핑되어있지 않기 때문에 발생했다고 할 수 있습니다. 그러나, 해당 변수를 State 로 래핑하고 추가적으로 관련 코드를 작성하게 된다면 너무나 많은 변경이 발생하고, 가독성 또한 저하됩니다. 

 

그러므로, 변수를 State 로 래핑하는 것보다 깊은 복사를 통해 변경이 필요한 아이템만 변경시켜주는 방식을 채택할 수 있습니다.

 

전체 리스트를 순회하며 매핑하는 과정을 거치기 때문에, 불필요한 렌더링이 수행되어 성능상의 이슈가 있지는 않을까 걱정했으나, Composable 은 유연하고 효율적이기 때문에 이전에 호출했던 Composable 을 추가 호출하지 않습니다. 관련된 설명은 다음 공식 문서에서 확인하실 수 있습니다.

 

 

컴포저블 수명 주기  |  Jetpack Compose  |  Android Developers

컴포저블 수명 주기 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 이 페이지에서는 컴포저블의 수명 주기에 관해 알아보며 Compose에서 컴포저블에 재구성

developer.android.com