[Android,Paging] Compose에서 Paging Library 구현하기 (1)

 

Paging 라이브러리

Paging 라이브러리는 대규모 데이터 세트에서 페이징 된 데이터를 로드하여 표시하는 기능을 제공한다.

Paging 라이브러리를 사용해서 네트워크 데이터 소스에서 페이징 된 데이터의 스트림을 설정하고,

Compose View에 표시하는 방법을 학습했다.

 

우선 아래와 같이 Paging 관련 Library를 추가한다.

    // paging
    def paging_version = "3.1.1"
    implementation "androidx.paging:paging-runtime:$paging_version"
    implementation "androidx.paging:paging-compose:1.0.0-alpha18"

 

대부분의 페이징 라이브러리는 서버와 로컬 DB를 함께 사용하므로, Room과 Retrfit 라이브러리도 추가해준다.

https://jinudmjournal.tistory.com/130

 

[Android, Room] Room Database 스터디 기록 (2)

Room Database 스터디 기록 (1) https://jinudmjournal.tistory.com/129 [Android, Room] Room Database 스터디 기록 (1) https://developer.android.com/training/data-storage/room?hl=ko#components Room을 사용하여 로컬 데이터베이스에 데이

jinudmjournal.tistory.com

 

    // room
    def room_version = "2.5.1"
    implementation "androidx.room:room-runtime:$room_version"
    implementation "androidx.room:room-ktx:$room_version"
    kapt "androidx.room:room-compiler:$room_version"
    implementation "androidx.room:room-paging:$room_version"
    testImplementation "androidx.room:room-testing:$room_version"

    // retrofit , okkhttp
    implementation "com.squareup.okhttp3:okhttp3:4.10.0"
    implementation "com.squareup.retrofit2:retrofit:2.9.0"
    implementation "com.squareup.retrofit2:converter-gson:2.9.0"

 

페이징 라이브러리 아키텍처

Paging 라이브러리는 저장소, viewModel, UI 세 가지 레이어에서 작동한다.

페이징 라이브러리가 앱 아키텍처에 적용되는 방식

각 레이어에서 작동하는 페이징 라이브러리 구성요소와 이 구성요소가 함께 작동하여 페이징된 데이터를 로드하고 표시한다.

 

우선 저장소 레이어부터 살펴보자면, PagingSource 구성요소를 활용한다.

PagingSource 객체는 데이터 소스와 이 소스에서 데이터를 검색하는 방법을 정의한다.

PagingSource 객체는 네트워크 소스 및 로컬 데이터베이스를 포함한 단일 소스에서 데이터를 로드할 수 있다.

 

다른 페이징 라이브러리로는 RemoteMediator가 있다.

RemoteMediator 객체는 로컬 데이터베이스 캐시가 있는 네트워크 데이터 소스와 같은 계층화된 데이터 소스의 페이징을 처리한다.

 

ViewModel 레이어에서는 PagingData 구성요소를 활용한다.

Pager 구성 요소는  PagingSource 객체 및 PagingConfig 구성 객체를 바탕으로 반응형 스트림에 노출되는

PagingData 인스턴스를 구성하기 위한 공개 API를 제공한다.

 

PagingData 객체는 페이지로 나눈 데이터의 스냅샷을 보유하는 컨테이너이다.

PagingSource 객체를 쿼리하여 결과를 저장한다.

 

마지막으로 UI 레이어가 있다. 

UI 레이어는 기본 페이징으로 나누어진 데이터를 처리하는 레이어이며, compose에서는 LazyColum 리스트를 구성한다.

 

 

Paging 구현 순서

이 포스팅에서 사용하는 Paging 구현 순서는 아래와 같다.

1. Data Model을 정의한다. 

   - Entity, Dto, Domain Model, Mappers.. 

2. RoomDB를 구현한다.

3. Retrofit 등 리모트 서버에 데이터를 요청하고 받는 코드를 구현한다.

4. RemoteMediator를 생성한다.

   - 외부 서버에서 받은 데이터를 DB로 넘겨주는 역할을 한다.

   - 페이지 단위의 데이터를 주고 받을 때 DB와 서버 측에서 처리할 일을 구현하는 역할을 한다.

5. Room DB의 Dao와 Repository에서 Pager를 return할 함수를 정의한다.

   - 여기서 정의한 함수는 Flow 타입이어야 한다.

6. ViewModel에서 PagingData를 collect하고, LazyColumn에서 데이터를 보여준다.

 

 

1. Data Model 정의

 

Entity

RoomDB의 Entity 클래스를 정의한다.

Paging 처리를 하기 전에, RoomDB를 구현하는 것이 좋다.

@Entity(tableName = "items")
data class ItemEntity(
    @PrimaryKey val id : Int,
    val name : String
)

 

Dto

서버에서 데이터를 받아올 때 사용하는 데이터 클래스이다.

일반적으로 Gson이나 Moshi를 통해서 JSON 타입의 데이터를 받으므로, 서버에서 받을 데이터 형식을 정의한다.

 

data class ItemDto(
    val id : Int,
    val name : String
)

 

Model

도메인 모델로, 앱에서 사용하는 데이터 클래스이다.

 

data class Item(
    val id : Int,
    val name : String
)

 

앱에서 데이터를 다룰 때, DB의 Entity나 서버의 Dto 클래스만으로는 모든 데이터 형식을 나타내기 어렵다.

따라서 앱 내의 DB를 서버의 데이터 클래스로부터 분리하기 위한 목적으로 도메인 클래스를 정의한다.

위 예제에서는 Model과 Dto가 같지만, 실제 데이터를 다룰 때는 Model에 더 구체적인 데이터가 포함된다.

 

Mapping 함수

각 데이터 클래스를 사용할 때마다 수정하는 것은 비효울적인 데이터 접근이 될 것이다.

이를 해결하기 위해서 Mapping 함수를 별도로 두어서 사용하게 되는데, 

서버의 데이터를 다루는 Dto 타입의 데이터를 Entity 타입의 데이터로 변형해야 할 경우가 생긴다.

반대의 경우도 발생할 수 있으며, 이를 대비해서 미리 변환 함수를 제작한다.

 

// dto ->  entity
fun ItemDto.toItemEntity() : ItemEntity{
    return ItemEntity(
        id = id,
        name = name
    )
}

// entity -> dto
fun ItemEntity.toItemDto() : ItemDto {
    return ItemDto(
        id = id,
        name = name
    )
}

 

 

이제 Paging 라이브러리를 구현하기 위해서 필요한 데이터 모델을 모두 정의했다.

다음 포스팅을 통해서 실제로 서버에서 데이터를 받아와서 페이징 처리를 하는 방법을 학습한다.