본문 바로가기

안드로이드/Compose Paging3

[안드로이드 Jetpack Compose Paging3 시리즈] RemoteMediator 구현하기 #9


1. RemoteMediator 구현하기

안녕하세요. 지난 포스팅에서는 안드로이드 Jetpack Compose Paging3 라이브러리를 사용할 때 로컬 데이터베이스와 상호작용하기 위한 Local Data Source를 구현했습니다.

이번 포스팅에서는 네트워크를 통해 가져온 데이터를 로컬 데이터베이스에 저장하기 위해 RemoteMediator를 구현하겠습니다.

MovieLocalDataSource와 MovieRemoteMediator를 추가한 모습
MovieLocalDataSource와 MovieRemoteMediator를 추가한 모습

2. RemoteMediator란?

RemoteMediator는 안드로이드 Jetpack Compose의 Paging3 라이브러리의 핵심 컴포넌트 중 하나로, 네트워크와 로컬 데이터베이스 간의 데이터 동기화를 담당합니다. 네트워크에서 데이터를 가져온 후 로컬 데이터베이스에 저장하고, 이 데이터를 PagingSource를 통해 UI에 제공하는 역할을 합니다. RemoteMediator를 사용함으로써, 앱은 네트워크 연결 상태에 관계없이 지속적으로 데이터를 제공할 수 있으며, 데이터의 캐싱과 동기화를 효율적으로 관리할 수 있습니다.

2-1. RemoteMediator 생성

네트워크와 로컬 데이터베이스의 동기화를 진행하기 위해서 RemoteMediator를 만들겠습니다. 네트워크를 통해 가져온 데이터를 로컬 데이터베이스에 저장하기 위해서 지난 포스팅에서 구현한 LocalDataSource를 사용합니다. 아래 코드는 RemoteMediator 추상 클래스를 구현한 MovieRemoteMediator입니다. 스크롤 상태에 따라 page 정보를 얻어오고 있으며, page 정보를 이용하여 네트워크 통신을 하고 있습니다. 그 후, local.saveMovies() 함수의 호출을 통해 로컬 데이터베이스에 데이터를 저장합니다. 

 

// MovieRemoteMediator.kt

private const val MOVIE_START_PAGE_INDEX = 1

@OptIn(ExperimentalPagingApi::class)
class MovieRemoteMediator(
    private val local: MovieDataSource.Local,
    private val remote: MovieDataSource.Remote
) : RemoteMediator<Int, MovieDbData>() {
    
    override suspend fun load(loadType: LoadType, state: PagingState<Int, MovieDbData>): MediatorResult {
        val page = when (loadType) {
            LoadType.REFRESH -> MOVIE_START_PAGE_INDEX
            LoadType.PREPEND -> return MediatorResult.Success(endOfPaginationReached = true)
            LoadType.APPEND -> local.getLastRemoteKey()?.nextPage ?: return MediatorResult.Success(endOfPaginationReached = true)
        }

        remote.getMovies(page, state.config.pageSize).getResult({ successResult ->
            if (loadType == LoadType.REFRESH) {
                local.clearMovies()
                local.clearRemoteKeys()
            }

            val movies = successResult.data

            val endOfPaginationReached = movies.isEmpty()

            val prevPage = if (page == MOVIE_START_PAGE_INDEX) null else page - 1
            val nextPage = if (endOfPaginationReached) null else page + 1

            val key = MovieRemoteKeyDbData(prevPage = prevPage, nextPage = nextPage)

            local.saveMovies(movies)
            local.saveRemoteKey(key)

            return MediatorResult.Success(endOfPaginationReached = endOfPaginationReached)
        }, { errorResult ->
            return MediatorResult.Error(errorResult.error)
        })
    }
}

3. RemoteMediator 적용 정리

이번 포스팅에서는 LocalDataSource와 RemoteMediator를 구현했습니다. 이제 Pager 객체에 RemoteMediator와 PagingSource만 제공하면 Paging3 라이브러리가 자동으로 페이징 데이터를 전달합니다.

다음 포스팅에서는 Paging3 라이브러리에서 제공하는 RemoteMediator에 있는 LoadType.REFRESH, LoadType.PREPEND, LoadType.APPEND, MediatorResult 등에 대해 설명하겠습니다.

반응형