최근 기존에 개발된 앱을 코틀린으로 마이그레이션 하고 리팩토링 작업을 진행 하고있습니다. 코루틴을 사용하지 않았던 기존 앱은 SQLITE Query 실행 완료 타이밍에 맞춰 RecyclerView List 변경을 어떻게 하면 좋을지 많은 고민과 이게 맞나? 싶은 부분이 많았지만 우여곡절 끝에 릴리즈 하고 안정화했었는데, 이번에 코루틴 Flow을 적용하면서 이게 맞나?라는 고민 또한 해결되었습니다.
1. ListAdapter 도입 이유
또한 효율적인 RecyclerView 관리를 위해 ListAdapter를 도입하기로 했습니다.
기존의 RecyclerView는 DataSetChanged()를 이용해서 전체 Item을 갱신하도록 하는데, 갱신 비용이 많이 들어갑니다. 문제 해결법으로 DiffUtil을 사용하면 리스트 아이템의 변경 부분을 체크하고 변경된 부분만 갱신하므로 따로 notify가 필요 없고 갱신 비용을 절약할 수 있습니다. (단, 전체 리스트를 확인하기 때문에 notifyItemChanged, notifyItemInserted, notifyItemRemoved 같은 경우보다는 효율적이지는 못하다는 단점이 있습니다.)
기본적으로 DiffUtil만 사용하면 포그라운드에서 동작합니다. DiffUtil의 시간 복잡도는 O(N + D^2) 이므로 대량의 데이터에서는 ANR이 발생할 수 있습니다. 데이터의 양이 많다면(기본적으로 약 item > 1000) 백그라운드에서 동작하도록 AsyncListDiffer를 사용해야 하는데, 구글에서는 아예 AsyncListDiffer를 내장한 ListAdapter로 Recyclerview.Adapter를 대체해서 사용할 수 있게 해줬습니다.
2. 문제점 발생
ListAdapter는 Immutable한 List를 사용하기 때문에 itemMove시 Collections.swap이 불가한 문제가 발생했습니다.
3. 해결 방법
override fun onItemMove(fromPosition: Int, toPosition: Int){
val list = currentlist.toMutableList()
Collections.swap(list, fromPosition, toPosition)
submitList(list)
}
4. 결론
구글 검색으로 위와 같은 해결 방법을 찾아 적용해 봤는데, onItemMove는 Drag 한 상태로 Item과 Item 사이에 걸쳐있으면 무한 반복되어 계속 submitList를 요청하는 문제가 있었습니다. 그로 인해 Drag가 원치않게 끊기는 경우도 있었습니다. List의 Item 수가 작으면 상관은 없겠지만 결국 ListAdapter 사용은 하되 ListAdapter에서는 ItemTouchHelper를 제공하지 않기로 하고 순서 변경 버튼을 Activity 내에 추가해서 RecyclerView.adapter가 적용된 adapter를 recyclerView에 붙여서 순서 변경 기능을 제공하기로 했습니다.
'안드로이드' 카테고리의 다른 글
[안드로이드] SQLite Cursor 사용에 관한 고찰 (0) | 2023.03.23 |
---|---|
[안드로이드] 서비스 startCommand에 관하여 (0) | 2022.01.17 |
[안드로이드] 애니메이션 Interpolator 에 관하여 (0) | 2021.12.17 |
[안드로이드] Android studio Arctic Fox 버전 이후 gradle allprojects 추가방법 (0) | 2021.11.10 |