/////
Search

맛집 조회 API에 대해 정렬 및 페이징 반영

모바일
담당자
마감일
2022/03/02
마일스톤
상태
완료
작성일
2021/10/31 11:00

Paging

페이징은 데이터베이스의 데이터를 일정한 개수로 나눠서 제공하는 것을 의미한다. 서버-클라이언트 모델에서는 주로 서버에서 페이징을 구현한 후, 클라이언트를 통해 사용자가 열람한 페이지의 정보를 보여주는 것이 일반적이다. 예를 들어, 구글 검색에서 android 키워드를 검색 했을때 약 40억 개의 해당하는 모든 검색 결과를 클라이언트에게 보내는 것이 아닌 상위 10개의 결과만 보여준다.
이로써, 구글은 사용자에게 원하는 결과를 빠르고 신속하게 제공하여 성능, 메모리, 네트워크 비용을 효과적으로 다룰 수 있다. 만약 페이징을 사용하지 않는다면 서버 측에서는 여러 테이블에 저장된 데이터를 모든 스캔하여 비효율적인 상황을 맞이하게 되고, 클라이언트에서는 제한된 자원으로 이를 보여주지 못할 가능성이 높다.
그러므로 페이징은 서버에서 대량의 데이터를 제공하는 보편적인 방법이다. 서버 개발자는 REST API를 디자인할 때, 다음과 같이 사용자가 열람한 페이지의 데이터만 가져올 수 있도록 API를 설계한다.
//예시 GET /api/search?page=2&per_page=10 GET /api/jeju/store?page=4&per_page=15 ...
Kotlin
복사

방향성

Repository Layer

PagingSource
데이터 소스와 해당 소스에서 데이터를 검색하는 방법을 정의한다. 네트워크 소스 및 로컬 데이터베이스를 포함한 단일 소스에서 데이터를 로드할 수 있다.
class StorePagingSource ( private val service: RestaurantService ) : PagingSource<Int, StoreList> { override suspend fun load(params: LoadParams<Int>): LoadResult<Int, RestaurantList> { return try { val nextPage = params.key ?: 0 val response = if(nextPage <= 10) { ... } else { ... } LoadResult.Page( data = response.first, prevKey = null, nextKey = null ) } catch (e: Exception) LoadResult.Error(...) } override fun getRefreshKey(state: PagingState<Int, RestaurantList>): Int? { ... } }
Kotlin
복사
load 메서드는 params를 바탕으로 페이지의 데이터를 반환한다. params의 key 값이 얻고자 하는 페이지의 정보이고, loadSize의 정보도 포함한다. LoadResult의 Page와 Error가 존재하는데, Page는 정상적인 경우에 사용한다. 위의 예제처럼 다음 데이터를 더 이상 호출하지 않으려면 nextKey 값을 null로 선언한다. Error는 보기 그대로 Exception 발생이나 데이터가 문제가 있을 경우 사용한다.
getRefreshKey 메서드는 refresh 시 다시 시작할 key를 반환한다. 즉, 로드된 페이지 데이터의 중간에서 새로 고침할 때 다시 시작하는 방법을 정의하는 부분이다. state 파라미터는 PagingState 타입으로 로드된 페이지 및 마지막으로 액세서 한 위치 등의 페이징 시스템의 스냅샷 상태를 가지고 있다.
RepositoryImpl
Pager와 PagingSource를 사용하여 PagingData로 반환한다. PagingConfig로 페이지의 기본 설정을 정의한 후 Pager 객체를 생성한다.
override suspend fun getRestaurantList(): Pager<Int, RestaurantList> { return Pager(PagingConfig(pageSize = 5)) { pagingSource } }
Kotlin
복사

ViewModel Layer

Repository의 메서드를 호출하고 Model의 업데이트 된 리스트를 받아 업데이트 하여 UI Layer에게 데이터를 넘긴다.

UI Layer

Fragment
사용할 RecyclerView의 addOnScrollListener 를 추가하여 현재 화면에 출력된 리스트 중 마지막 View의 position을 감지하거나 findLastCompletelyVisibleItemPosition 를 사용하여 모든 아이템 중 최상단이 완전히 보이는 가장 상위의 아이템의 포지션을 감지하여 업데이트 한다.
PagingAdapter → ListAdapter
submitList override 하여 반환된 리스트를 모두 업데이트하는 것이 아닌 currentList를 추가한 후 newList를 업데이트한다.

구현

밑으로 스크롤 시 리스트 불러오기(페이지 개수는 미정)
화면 회전 시 데이터 저장하여 사용하기(구현 중)
페이지 개수 ViewModel에서 관리하기(구현 중)