Jetpack Paging3 - 2. DataSource 정의하기
이번 포스팅부터는 Android Developers에서 제공하는 Paging3 Codelab을 진행하면서 공부한 내용이 포함됩니다.
⚜️ PagingSource
DataSource를 정의하기 위해 구현하는 PagingSource 클래스와 사용되는 메서드에 대해 알아봅니다.
DataSource를 정의하기 위해 구현하는 PagingSource 클래스와 사용되는 메서드에 대해 알아봅니다.
DataSource를 식별하기 위해 먼저, PagingSource
를 정의해야 합니다. PagingSource
에는 대표적으로 아래 항목들을 정의합니다
-
페이징 key의 유형
-
로드된 Data의 유형
-
데이터를 가져오는 위치
PagingSource<Key, Value>
에는 Key
와 Value
를 지정해야 합니다. 여기서 Key는 데이터를 로드하는데 사용되는 식별자 유형을 정의하며 Value는 데이터 자체의 유형입니다. 즉, DataSource를 정의하기 위해 Key와 반환 Data를 Generic으로 받습니다.
Codelab에서는 GitHub API를 사용하여 Repository를 페이징하는 실습을 진행합니다. GitHub API에서 페이지 1을 기반으로 하는 번호를 사용하기 때문에 페이징 Key의 유형은 Int
입니다. 로드된 데이터의 유형으로는 Network Response에 해당하는 Repo
data class를 사용합니다.
추가로 데이터를 가져오기 위한 API 인터페이스를 생성자로 제공하게 됩니다. Codelab에서는 해당 인터페이스인 GithubService를 생성자로 전달합니다.
class GithubPagingSource(
private val service: GithubService,
private val query: String
) : PagingSource<Int, Repo>() {
override fun getRefreshKey(state: PagingState<Int, Repo>): Int? {
@TODO
}
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Repo> {
@TODO
}
}
✅ load()
load()
함수는 실제 데이터를 가져오는 로직을 구현하는 함수입니다. 간단하게, 사용자가 데이터 열람을 위해 스크롤 시 표시할 데이터를 비동기식으로 가져오기 위해 사용된다고 볼 수 있습니다.
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Repo> {
val position = params.key ?: GITHUB_STARTING_PAGE_INDEX
val apiQuery = query + IN_QUALIFIER
return try {
val response = service.searchRepos(apiQuery, position, params.loadSize)
val repos = response.items
val nextKey = if (repos.isEmpty()) {
null
} else {
position + (params.loadSize / NETWORK_PAGE_SIZE)
}
LoadResult.Page(
data = repos,
prevKey = if (position == GITHUB_STARTING_PAGE_INDEX) null else position - 1,
nextKey = nextKey
)
} catch (e: IOException) {
return LoadResult.Error(e)
} catch (e: HttpException) {
return LoadResult.Error(e)
}
}
parameter로 LoadParams
객체가 전달되는데 아래 항목들이 포함됩니다.
-
LoadParams.key
로드할 페이지의 Key에 해당합니다. 처음 로드될 경우LoadParams.key
는null
에 해당됩니다. 초기 페이지 키를 직접 지정할 수 있습니다. -
LoadParams.loadSize
로드할 데이터 항목의 갯수를 정의합니다.
load()
함수는 데이터 로드 결과에 대한 LoadResult
sealed class를 반환합니다. LoadResult
에 대한 예외 처리가 필요합니다.
-
LoadResult.Page
데이터 로드 성공 시 -
LoadResult.Error
데이터 로드 실패 시
✅ getRefreshKey()
getRefreshKey()
함수는 초기 Key값이나 데이터 로드 중단 후 재 로드시 이전 Position에서 중단된 Key값을 가져오는 등 load()
에 필요한 Key값을 가져오는데 사용되는 함수입니다. 따라서, load()
이전에 반드시 선행되는 함수라고 볼 수 있습니다. PagingState
객체를 parameter로 취하고 데이터가 첫 로드 후 새로 고침되거나 무효화 되었을 때 Key를 반환하여 load()
로 전달하게 됩니다.
override fun getRefreshKey(state: PagingState<Int, Repo>): Int? {
return state.anchorPosition?.let { anchorPosition ->
state.closestPageToPosition(anchorPosition)?.prevKey?.plus(1)
?: state.closestPageToPosition(anchorPosition)?.nextKey?.minus(1)
}
}
만약 prevKey
가 null
일 경우 첫 번째 Page를 반환하고 nextKey
가 null
일 경우 마지막 Page를 반환합니다. 가져올 데이터가 없는 경우 (prevKey
와 nextKey
모두 null
일 경우) null
을 반환하게 됩니다. 여기서 anchorPosition
은 가장 최근에 액세스한 index입니다.
아래는 load()
함수가 각 Key를 수신하고 후속으로 로드할 Key를 제공받는 방법입니다.
⚜️ RemoteMediator
Network에서 데이터 로드와 로드된 데이터를 로컬 데이터베이스에 캐싱하는 역할을 하는 RemoteMediator에 대해 알아봅니다.
Network에서 데이터 로드와 로드된 데이터를 로컬 데이터베이스에 캐싱하는 역할을 하는 RemoteMediator에 대해 알아봅니다.
PagingSource
는 Network 작업을 통해 가져온 데이터에 대한 작업을 정의하지만RemoteMediator
를 추가로 사용할 경우 가져온 데이터를 캐싱할 수 있는 기능을 제공합니다. 따라서, RemoteMediator
를 사용하게 되면 PagingSource
는 캐시된 데이터만을 사용하게 되며 UI에서 처리되는 데이터를 처리하게 됩니다.
RemoteMediator
에 구현에 대한 자세한 내용은 다음 포스팅에서 확인할 수 있습니다.
⚜️ References
Android Developers 공식 문서
찰스님 블로그
Author And Source
이 문제에 관하여(Jetpack Paging3 - 2. DataSource 정의하기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@jslee-dev/Jetpack-Paging3-2.-DataSource-정의하기저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)