[안드로이드 Jetpack Compose Paging3 시리즈] PagingConfig, PagingSource 적용하기 #3

2024. 2. 21. 11:30·안드로이드/Compose Paging3
반응형

1. Paging 데이터 스트림 구현

안녕하세요. 이번 포스팅에서는 안드로이드 Jetpack Compose Paging3 라이브러리의 PagingConfig와 PagingSource를 구현해서 페이징 데이터 스트림을 구현하겠습니다. MovieApi Interface에 영화 리스트를 불러오는 함수를 정의한 후, MovieRepository에 PagingConfig와 PagingSource를 적용해서 Pager 객체를 만들겠습니다. DB 캐싱은 제외한 페이징을 구현할 것이기 때문에 RemoteMediator는 구현하지 않아도 됩니다. 

페이징 다이어그램
페이징 다이어그램

1-1. MovieApi 및 MovieRemoteDataSource에 getMovies 함수 정의

네트워크 통신을 통해 영화 목록을 불러오기 위해 retrofit interface에 getMovies() 함수를 정의하고, 이를 불러오는 RemoteDataSource 영역에서도 getMovies 함수를 정의 및 구현하겠습니다.

interface MovieApi {
    @GET("/movies?&_sort=category,id")
    suspend fun getMovies(
        @Query("_page") page: Int,
        @Query("_limit") limit: Int,
    ): List<MovieData>
}
interface MovieDataSource {
    interface Remote {
        suspend fun getMovies(page: Int, limit: Int): ApiResult<List<MovieEntity>>
    }
}

class MovieRemoteDataSource(
    private val movieApi: MovieApi
) : MovieDataSource.Remote {
    override suspend fun getMovies(page: Int, limit: Int): ApiResult<List<MovieEntity>> = try {
        val result = movieApi.getMovies(
            page = page,
            limit = limit
        )
        ApiResult.Success(result.map { it.toDomain() })
    } catch (e: Exception) {
        ApiResult.Error(e)
    }
}

1-2. MovieRepository에서 Pager 생성

MovieRepository에 Pager 객체를 만들어서 데이터 스트림을 반환해야 합니다. 이전 포스팅에서 설명한 것처럼 Pager에 PagingConfig 및 PagingSource를 전달해 줍니다. 이번에는 DB 캐싱 처리는 하지 않기 때문에 RemoteMediator는 구현하지 않아도 됩니다.  

class MovieRepositoryImpl(private val remote: MovieDataSource.Remote) : MovieRepository {
    override fun movies(pageSize: Int): Flow<PagingData<MovieEntity>> {
        return Pager(
            config = PagingConfig(
                pageSize = pageSize,
                enablePlaceholders = false,
            ),
            pagingSourceFactory = { MoviesPagingSource(remote) }
        ).flow
    }
}

class MoviesPagingSource(
    private val remote: MovieDataSource.Remote
) : PagingSource<Int, MovieEntity>() {

    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, MovieEntity> {
        val page = params.key ?: 1
        return remote.getMovies(page, params.loadSize).getResult({
            LoadResult.Page(
                data = it.data,
                prevKey = if (page == 1) null else page - 1,
                nextKey = if (it.data.isEmpty()) null else page + 1
            )
        }, {
            LoadResult.Error(it.error)
        })
    }
    override fun getRefreshKey(state: PagingState<Int, MovieEntity>): Int? {
        return state.anchorPosition?.let { anchorPosition ->
            state.closestPageToPosition(anchorPosition)?.prevKey
        }
    }
}

PagingSource 추상클래스를 상속받아서 MoviesPagingSource 클래스를 pagingSourceFactory로 전달하고 있습니다. load 및 getRefreshKey 함수를 재정의 해야 하는데, load 함수에서는 LoadResult.Page 또는 LoadResult.Error를 반환해야 합니다. getRefreshKey()는 refresh시 다시 시작할 key를 반환해 주면 됩니다.

1-3. UseCase를 만들고 UI Layer에서 데이터 스트림 구독

저는 Domain Layer를 구현했기 때문에 MovieRepository의 접근을 UseCase에서 하고 있습니다. 그래서 영화 목록 데이터 스트림을 반환하는 GetMoviesUseCase를 만들고, 이를 ViewModel에서 불러와서 데이터 스트림을 받도록 구현했습니다.

class GetMovies (
    private val movieRepository: MovieRepository
){
    operator fun invoke(pageSize: Int): Flow<PagingData<MovieEntity>> = movieRepository.movies(pageSize)
}

@HiltViewModel
class MovieListViewModel @Inject constructor(
    private val getMovies: GetMovies,
    savedStateHandle: SavedStateHandle,
) : ViewModel() {
    init {
        viewModelScope.launch {
            getMovies(20).cachedIn(viewModelScope).collectLatest { pagingData ->
                
            }
        }
    }
}

2. PagingConfig, PagingSource, 데이터스트림 구독 정리

이번 시간에는 안드로이드 Jetpack Compose Paging3 라이브러리의 Pager 객체를 만들고 데이터 스트림을 ViewModel에서 구독하는 기능까지 구현했습니다. Pager 객체를 만들기 위해서 PagingConfig와 PagingSource를 구현하였고, PagingSource의 load() 함수에서는 네트워크 통신을 통해 페이징 데이터를 가져올 수 있도록 MovieApi Interface에 정의한 getMovies() 함수를 호출했습니다.

ViewModel에서는 데이터 스트림을 구독해서 pagingData를 받아올 수 있게 되었습니다. xml기반으로 작업을 한다면 RecyclerView의 Adapter에 submit 함수에 pagingData를 전달하게 되며, Jetpack Compose로 작업을 한다면 Adapter 없이 LazyColumn을 통해 구현을 하게 됩니다.

다음 포스팅에서는 Jetpack Compose를 통해 pagingData를 화면에 보여주는 방법에 대해 설명하겠습니다.

저작자표시 비영리 변경금지

'안드로이드 > Compose Paging3' 카테고리의 다른 글

[안드로이드 Jetpack Compose Paging3 시리즈] RemoteMediator 파헤치기 #6  (0) 2024.02.24
[안드로이드 Jetpack Compose Paging3 시리즈] LazyVerticalGrid 구현 및 Navigation #5  (0) 2024.02.23
[안드로이드 Jetpack Compose Paging3 시리즈] LazyColumn 구현 #4  (0) 2024.02.22
[안드로이드 Jetpack Compose Paging3 시리즈] Paging3 라이브러리 구조 설명 #2  (0) 2024.02.20
[안드로이드 Jetpack Compose Paging3 시리즈] Paging3 라이브러리 소개 #1  (0) 2024.02.19
'안드로이드/Compose Paging3' 카테고리의 다른 글
  • [안드로이드 Jetpack Compose Paging3 시리즈] LazyVerticalGrid 구현 및 Navigation #5
  • [안드로이드 Jetpack Compose Paging3 시리즈] LazyColumn 구현 #4
  • [안드로이드 Jetpack Compose Paging3 시리즈] Paging3 라이브러리 구조 설명 #2
  • [안드로이드 Jetpack Compose Paging3 시리즈] Paging3 라이브러리 소개 #1
코딩덕
코딩덕
안드로이드, 리액트 등의 개발 노하우와 최신 AI 기술을 다루는 기술 블로그입니다. 실무 중심의 경험을 바탕으로 마주한 문제와 해결 과정을 체계적으로 기록하며, 개발자에게 실질적으로 도움 되는 프로그래밍 팁과 인사이트를 쉽고 명확하게 공유하고자 합니다.
  • 코딩덕
    개발자가 들려주는 IT 이야기
    코딩덕
  • 전체
    오늘
    어제
    • 분류 전체보기 (66)
      • 안드로이드 (62)
        • 멀티 모듈 (11)
        • 클린 아키텍처 (11)
        • 트러블 슈팅 (5)
        • 코틀린 (3)
        • 코루틴 (2)
        • Compose (1)
        • Compose UI (6)
        • Compose Dialog (8)
        • Compose Paging3 (11)
        • Compose State (2)
        • Util (1)
      • Github (3)
        • PR Template (2)
        • AI Code Review (1)
      • 리액트 (1)
        • NextJs (1)
  • 블로그 메뉴

    • 홈
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    Gradle
    ScrollView
    MutableState
    flow
    클린 아키텍처
    jsonadapter
    sealed class
    dynamic json
    paging3
    코루틴
    UI Layer
    OnBackPressedDispatcher
    Clean Architecture
    pager
    Usecase
    멀티 모듈
    enum class
    multi module
    안드로이드
    Dialog
    Github
    트러블슈팅
    recyclerview
    pr template
    Jetpack Compose
    ViewModel
    코틀린
    LazyRow
    ai code review
    데이터 레이어
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
코딩덕
[안드로이드 Jetpack Compose Paging3 시리즈] PagingConfig, PagingSource 적용하기 #3
상단으로

티스토리툴바