목차
- Intro
- 무한 스크롤 적용 계기
- 페이징 방식
- 기존 코드의 문제와 해결 방안
- Outro
이번 시리즈에서는 스타카토 프로젝트에 무한 스크롤을 적용하는 과정을 다룬다. 1편에서는 무한 스크롤을 적용하게 된 계기와 적용 전에 고려해야 할 사항들을 간단히 다룰 것이다.
카테고리 조회 시, 스타카토 목록의 썸네일 로딩 시간이 오래 걸리는 문제가 있다. 카테고리를 조회할 때 해당 카테고리에 속한 모든 스타카토 목록을 한 번에 조회하기 때문이다. 이러한 문제를 해결하고자, 필요할 때만 데이터를 불러오는 무한 스크롤 방식을 도입하게 되었다.
백엔드와 함께 Offset/Limit 방식과 Cursor 방식 두 가지를 고려했다.
Offset/Limit 방식은 특정 offset부터 limit 개수만큼 데이터를 조회하는 방식이다. 하지만 게시물이 추가되거나 삭제될 경우, 중복 조회 또는 누락이 발생할 수 있으며, offset이 커질수록 전체 데이터를 순회해야 하므로 성능에도 부담이 생긴다.
Cursor 방식은 클라이언트가 어디까지 데이터를 읽었는지를 기억하고, 그 지점부터 다음 데이터를 조회하는 방식이다. 최신순 정렬 시에도 (visitedAt, createdAt, id) 같은 고유값을 기준으로 안정적인 조회가 가능하여 중복이나 누락 없이 데이터를 불러올 수 있다.
따라서, 성능과 데이터 정확성을 고려해 Cursor 방식을 선택했다.
S24와 Note20 기준으로 화면에 한 번에 표시되는 스타카토는 최대 8개였다. 스크롤 시 매끄러운 사용자 경험을 위해, 데이터를 10개 단위로 불러오도록 결정했다.
👿 멀티 모듈과 Paging의 짙은 안드로이드 의존성
스타카토는 멀티 모듈 구조를 적용하여 app, data, domain, presentation 모듈로 구성되어 있다. 무한 스크롤을 구현하기 위해 Paging 라이브러리 사용을 고려하고 있는데, Paging은 안드로이드 의존성이 짙다는 문제가 있다.
현재 구조에서 Paging을 사용하려면 data, domain, presentation의 build.gradle.kts에 의존성을 추가해야 한다. domain 모듈에도 의존성이 필요한 이유는 Repository 인터페이스가 domain 계층에 존재하기 때문이다.
💡 해결방안
안드로이드 공식 문서를 확인해보니, 테스트를 위해 안드로이드 의존성이 없는 설정이 있었다. 이를 활용하여 domain에서 안드로이드 의존성이 생기는 문제를 해결해보고자 한다.
implementation("androidx.paging:paging-runtime:$paging_version")
// alternatively - without Android dependencies for tests
testImplementation("androidx.paging:paging-common:$paging_version")
👿 android:nestedScrollingEnabled="false" 설정으로 인한 페이징 미작동
NestedScrollView 안에 스타카토 목록 RecyclerView가 존재한다. 중첩 스크롤을 방지하기 위해 RecyclerView의 nestedScrollingEnabled 속성을 false로 설정해두었다.
이 경우 초기 데이터만 로드되고 페이징이 작동하지 않는다. 반대로 nestedScrollingEnabled을 true로 설정하면 페이징은 정상적으로 동작하지만 스크롤 시 버벅임이 발생한다.
💡 해결방안
화면 전체를 하나의 RecyclerView로 구성하는 방법도 고려했지만, 카테고리 기본 정보, 함께하는 사람들 목록, 스타카토 목록을 모두 포함하면 RecyclerView가 지나치게 무거워질 것 같다고 판단했다. 그래서 Jetpack Compose로 마이그레이션 하는 방법을 시도하려고 한다. 스타카토는 이미 새로운 기능을 Jetpack Compose로 구현하고 있어 Compose로 마이그레이션하는 방법이 추후 유지보수성이나 디자인 변경 측면에서 더 유연하다는 생각이 들었다.
다음 편부터는 본격적인 무한 스크롤 적용기를 들고 오겠다! Coming Soon~