Jetpack Paging 라이브러리는 말 그대로 하나의 문서를 분리된 페이지로 나누는 것.
즉, 데이터가 클 때 작은 단위로 쪼개서 사용하는 곳에 적용된다.
예를 들어 구글에 안드로이드를 검색했을 때 수십억개의 결과가 나온다.
이를 한 번에 전달한다면 엄청난 트래픽이 발생할 것이다.
따라서 검색 결과를 10개씩 페이징해서 보여준다.
안드로이드 공식문서에 따르면 대규모 데이터 세트의 데이터 페이지를 로드하고 표시할 수 있다고 나와있다.
직접 paging을 구현하려면 너무 어려운 점이 많기 때문에 구글에서는 paging 라이브러리를 발표했다!!
페이징은 프로젝트의 적절한 관심사를 분리를 요구하며 안드로이드 권장 아키텍처에 통합되도록 만들어졌으며,
위와 같이 작동된다.
개별데이터가 PagingSource로 변환돼서 Pager에게 전달되고, Pager는 PagingConfig에 정해진 크기대로 PagingSource를 묶어서 PagingData라는 덩어리를 만들고, PagingAdapter를 통해 데이터를 ui에 표시하게 된다.
이제 지금 프로젝트에 Paging을 적용해보자.
내가 관심있는 책을 Room에 저장해놓고 이를 불러올 때 Paging을 적용해서 불러오자.
implementation 'androidx.room:room-paging:2.4.2'
implementation 'androidx.paging:paging-runtime-ktx:3.1.1'
위와 같이 gradle에 추가하고,
Room에서 불러올 것이기 때문에 Dao클래스에서 다음과 같이 PagingSource로 반환하는 쿼리를 작성하자!
@Query("SELECT * FROM books")
fun getFavoritePagingBooks() : PagingSource<Int, Book>
이제 이를 불러오는 Repository에서 Pager를 정의하면서 Dao에 접근하는 코드를 작성하자.
override fun getFavoritePagingBooks(): Flow<PagingData<Book>> {
val pagingSourceFactory = { db.bookSearchDao().getFavoritePagingBooks()}
/*
페이저를 구현하기 위해서 PagingConfig 를 통해 파라메타를 전달
페이지사이즈, 데이터를 필요한 만큼 로딩할것이기 때문에 false,
메모리가 최대를 가질 수 있는 크기
*/
return Pager(
config = PagingConfig(
pageSize = PAGING_SIZE,
enablePlaceholders = false,
maxSize = PAGING_SIZE * 3
),
pagingSourceFactory = pagingSourceFactory
).flow //페이징 데이터 결과를 flow 로 만들어줌
}
무엇보다 Paging은 Flow를 지원하기 때문에 .flow를 통해 페이징 데이터 결과를 Flow로 반환한다.
또한, PagingConfig를 통해 세 개의 파라메타를 전달한다.
val favoritePagingBooks : StateFlow<PagingData<Book>> =
bookSearchRepository.getFavoritePagingBooks()
.cachedIn(viewModelScope) //코루틴이 데이터스트림을 캐시하고 공유가능하게끔 만들어줌.
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), PagingData.empty())
//ui 에서 감시해야하기 때문에 stateIn 을 써서 stateFlow 로 만듬
이제 viewModel에서 Repository에 있는 함수를 불러옴으로써 프래그먼트에서 이 값을 인지하여 어댑터에 저장한다.
viewLifecycleOwner.lifecycleScope.launch{
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED){
bookSearchViewModel.favoritePagingBooks.collectLatest {
bookSearchAdapter.submitData(it) //submitList 가 아님
}
}
}
프래그먼트에서 해당 코드처럼 어댑터에 관심있는 책을 PagingData로 받아 PagingAdapter에 집어넣어 ui에 표시하면끝!!
class BookSearchPagingAdapter : PagingDataAdapter<Book, BookSearchViewHolder>(BookDiffCallback){
override fun onBindViewHolder(holder: BookSearchViewHolder, position: Int) {
val pagedBook = getItem(position)
pagedBook?.let{ book -> //null 처리 추가
holder.bind(book)
holder.itemView.setOnClickListener{
onItemClickListener?.let { it(book)}
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BookSearchViewHolder {
return BookSearchViewHolder(
ItemBookPreviewBinding.inflate(LayoutInflater.from(parent.context), parent, false)
)
}
어댑터를 기존의 리스트어댑터가 아닌, PagingDataAdapter로 생성 후 프래그먼트에서 연결해주면 ui에 잘 연결이 되었다!
그럼 위에 Paging 권장 아키텍처처럼 구현한 것이다!!
'Android > JETPACK' 카테고리의 다른 글
[JETPACK개론] DataStore (0) | 2022.09.25 |
---|---|
[JETPACK개론] Navigation (0) | 2022.09.18 |
[JETPACK개론] WorkManager(5) + 주기적작업, 고유작업 (0) | 2022.09.17 |
[JETPACK개론] WorkManager(4) + 작업진행률 관찰 (0) | 2022.09.14 |
[JETPACK개론] WorkManager(3) + Chaining, Coroutine (0) | 2022.09.09 |