안드로이드

[코틀린] Paging3

이손안나 2022. 10. 10. 16:24

💡 Paging ?

시스템 리소스를 효율적으로 활용하기 위해서 일정한 페이지 사이즈 만큼 나눠서 데이터를 로딩하는 기능.

 

1. PagingSource 구현

- pagingSource<Key, Value> : 키는 데이터를 로드하는데 사용되는 식별자, 값은 데이터 자체의 유형

- load() : params.key로 다음 페이지 값 전달

- LoadResult : 로드 작업에 대한 결과

class TicketPagingSource(
    private val category: String?,
    private val sort: Array<String>,
    private val service: TicketApiService
) : PagingSource<Int, TicketDto>() {


    override fun getRefreshKey(state: PagingState<Int, TicketDto>): Int? {
        return state.anchorPosition?.let { anchorPosition ->
            state.closestPageToPosition(anchorPosition)?.prevKey?.plus(1)
                ?: state.closestPageToPosition(anchorPosition)?.nextKey?.minus(1)
        }
    }

    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, TicketDto> {
        return try {
            val next = params.key ?: 0
            val response = service.getTickets(category, next, 1, "${sort[0]},${sort[1]}")
            if (response.success && response.data.contents.isNotEmpty()) {
                LoadResult.Page(
                    data = response.data.contents,
                    prevKey = null,
                    nextKey = if (response.data.nextPage == -1) null else next + 1
                )
            } else {
                LoadResult.Page(
                    data = response.data.contents,
                    prevKey = null,
                    nextKey = null
                )
            }

        } catch (e: Exception) {
            LoadResult.Error(e)
        }
    }
}

2. PagingSource를 이용하여 flow 생성

- pageSize는 실제 서버에 요청하는 아이템 개수와 동일

class TicketRemoteDataSourceImpl @Inject constructor(
    private val service: TicketApiService
) : TicketRemoteDataSource {

    override fun getTicketsList(
        category: String?,
        size: Int,
        sort: Array<String>
    ): Flow<PagingData<TicketDto>> =
        Pager(
            config = PagingConfig(pageSize = size, enablePlaceholders = false),
            pagingSourceFactory = {
                TicketPagingSource(category = category, sort = sort, service)
            }
        ).flow
}

3. viewModel 에서 호출하기 

fun requestTickets(): Flow<PagingData<Ticket>> {
        return ticketsUseCase.getTickets(
            ticketCategory.value,
            1,
            when(ticketSort.value) {
                LATEST -> arrayOf(CREATED_AT, DESC)
                OLDEST ->arrayOf(CREATED_AT, ASC)
                HIGH_SCORE ->arrayOf(RATING, DESC)
                LOW_SCORE ->arrayOf(RATING, ASC)
                else -> emptyArray()
            }
        )
            .cachedIn(viewModelScope)
    }

4.