일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- MotionLayout
- liveData
- databinding
- Android
- SWIFTUI
- android13
- google play
- Kotlin
- RxKotlin
- Koin
- paging
- SwiftUI Tutorial
- Android 13
- 동영상
- junit
- MediaSession
- Reactive
- node.js
- GCP
- list
- 인앱결제
- node
- 테스트 자동화
- mysql
- Observable
- Animation
- PagingLib
- mvvm
- rx
- MediaPlayer
- Today
- Total
봄날은 갔다. 이제 그 정신으로 공부하자
Paging Library - Gather Paged Data 본문
이 글에서는 “Paging Library - Overview(als2019.tistory.com/8)”를 기반으로 앱의 아키텍처 요구에 맞게 앱의 데이터 로드 솔루션을 맞춤설정하는 방법을 설명합니다.
observable list 생성
일반적으로 UI 코드는 앱의 ViewModel에 있는 LiveData<PagedList> 개체(또는 RxJava2를 사용하고 있다면 Flowable<PagedList> 또는 Observable<PagedList> 개체)를 관찰합니다. 식별 가능한 개체는 앱 목록 데이터의 콘텐츠와 표시 간에 연결을 형성합니다.
이러한 식별 가능한 PagedList 개체 중 하나를 생성하려면 DataSource.Factory 인스턴스를 LivePagedListBuilder 또는 RxPagedListBuilder 개체에 전달해야 합니다. DataSource 개체는 단일 PagedList를 위한 페이지를 로드합니다.
Factory 클래스는 데이터베이스 테이블 무효화 및 네트워크 새로고침과 같은 콘텐츠 업데이트에 대응하여 새로운 PagedList 인스턴스를 생성합니다. Room Persistence Library는 DataSource.Factory 개체를 제공할 수 있다. 또는 개발자가 직접 Object를 빌드할 수도 있습니다.
아래 예제는 Room의 DataSource.Factory 빌드 기능을 사용하여 앱의 ViewModel 클래스에 새로운 LiveData<PagedList> 인스턴스를 생성하는 방법을 보여줍니다.
// ConcertDao
@Dao
interface ConcertDao {
// The Int type parameter tells Room to use a PositionalDataSource
// object, with position-based loading under the hood.
@Query("SELECT * FROM concerts ORDER BY date DESC")
fun concertsByDate(): DataSource.Factory<Int, Concert>
}
// ConcertViewModel
// The Int type argument corresponds to a PositionalDataSource object.
val myConcertDataSource : DataSource.Factory<Int, Concert> =
concertDao.concertsByDate()
val concertList = myConcertDataSource.toLiveData(pageSize = 50)
사용자 paging configuration 정의
LiveData<pagedList>를 더 자세히 구성하기 위해 사용자 페이징 구성을 정의할 수도 있으며 특히 다음 속성을 정의할 수 있습니다.
Paging Library가 앱의 데이터베이스에서 목록을 로드할 때 더 세밀하게 제어하려면 아래 예제와 같이 맞춤 Excutor 개체를 LivaPagedListBuilder에 전달해야 합니다.
// ConcertViewModel
val myPagingConfig = Config(
pageSize = 50,
prefetchDistance = 150,
enablePlaceholders = true
)
// The Int type argument corresponds to a PositionalDataSource object.
val myConcertDataSource : DataSource.Factory<Int, Concert> =
concertDao.concertsByDate()
val concertList = myConcertDataSource.toLiveData(
pagingConfig = myPagingConfig,
fetchExecutor = myExecutor
)
정확한 Data source type 선택
아래 설명과 같이 Data source의 구조를 가장 잘 처리하는 Data source에 연결하는 것이 중요합니다.
데이터가 잘 못 되었을 때 알림
Paging Library를 사용 중이라면 테이블 또는 행이 오래되었을 때 앱의 다른 레이어에 알릴지는 데이터 영역에 따라 달라지며 알림을 받을 수 있도록 설정하려면 앱과 관련하여 선택한 DataSource 클래스에서 invalidata()함수를 호출합니다.
사용자 Data Source 빌드
Custom local data 솔루션을 사용하거나 네트워크에서 직접 데이터를 로드한다면 DataSource 서브클래스 중 하나를 구현할 수 있습니다. 아래 예제는 Concert의 시작 시간에 가져오는 데이터 소스를 보여줍니다.
class ConcertTimeDataSource() :
ItemKeyedDataSource<Date, Concert>() {
override fun getKey(item: Concert) = item.startTime
override fun loadInitial(
params: LoadInitialParams<Date>,
callback: LoadInitialCallback<Concert>) {
val items = fetchItems(params.requestedInitialKey, params.requestedLoadSize)
callback.onResult(items)
}
override fun loadAfter(
params: LoadParams<Date>,
callback: LoadCallback<Concert>) {
val items = fetchItemsAfter(
date = params.key,
limit = params.requestedLoadSize)
callback.onResult(items)
}
}
구체적인 DataSource.Factory 서브클래스를 생성함으로써 맞춤설정된 데이터를 PagedList 개체에 로드할 수 있습니다.
아래 예제는 위 예제에서 정의된 Custom Data source의 새 인스턴스를 생성하는 방법을 보여줍니다.
class ConcertTimeDataSourceFactory :
DataSource.Factory<Date, Concert>() {
val sourceLiveData = MutableLiveData<ConcertTimeDataSource>()
var latestSource: ConcertDataSource?
override fun create(): DataSource<Date, Concert> {
latestSource = ConcertTimeDataSource()
sourceLiveData.postValue(latestSource)
return latestSource
}
}
콘텐츠 업데이트 작동 방식 고려 사항
식별 가능한 PagedList 개체를 구성할 때 콘텐츠 업데이트 작동 방식을 고려해야 합니다.
Room Database에서 직접 데이터를 로드하면 업데이트가 앱의 UI로 자동 푸시됩니다.
페이징된 네트워크 API를 사용할 때 일반적으로 '스와이프하여 새로고침'과 같은 사용자 상호작용은 가장 최근에 사용된 DataSource를 무효화하는 신호로 사용되며, 무효화되면 데이터 소스의 새 인스턴스를 요청합니다.
아래 예제는 이러한 동작들을 보여줍니다.
class ConcertActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// ...
concertTimeViewModel.refreshState.observe(this, Observer {
// Shows one possible way of triggering a refresh operation.
swipeRefreshLayout.isRefreshing =
it == MyNetworkState.LOADING
})
swipeRefreshLayout.setOnRefreshListener {
concertTimeViewModel.invalidateDataSource()
}
}
}
class ConcertTimeViewModel(firstConcertStartTime: Date) : ViewModel() {
val dataSourceFactory = ConcertTimeDataSourceFactory(firstConcertStartTime)
val concertList: LiveData<PagedList<Concert>> =
dataSourceFactory.toLiveData(
pageSize = 50,
fetchExecutor = myExecutor
)
fun invalidateDataSource() =
dataSourceFactory.sourceLiveData.value?.invalidate()
}
데이터 매핑 제공
Paging Library는 DataSource에 의해 로드된 항목의 항목 기반 및 페이지 기반 변환을 지원합니다.
아래 예제에서 Concert 이름과 Concert 날짜의 조합은 이름과 날짜가 모두 포함된 단일 문자열로 매핑됩니다.
class ConcertViewModel : ViewModel() {
val concertDescriptions : LiveData<PagedList<String>>
init {
val concerts = database.allConcertsFactory()
.map "${it.name} - ${it.date}" }
.toLiveData(pageSize = 50)
}
}
}
위 예제는 항목이 로드된 후 항목을 래핑, 변환 또는 준비하려는 경우에 유용할 수 있습니다.
이 작업은 fetch executor에서 실행되기 때문에 디스크에서 읽거나 별도의 데이터베이스를 쿼리하는 것과 같이 리소스를 많이 사용하는 작업을 실행하게 될 수 있습니다.
'Android jetpack' 카테고리의 다른 글
MVVM + Koin 최소 샘플 앱 개발 - part 1 (0) | 2020.12.04 |
---|---|
Paging Library - Display paged lists (0) | 2020.11.24 |
Paging Library - Overview (0) | 2020.11.24 |
WorkManager 알아보기 (0) | 2020.11.23 |
Android 백그라운드 처리 가이드 (0) | 2020.11.23 |