https://medium.com/tech-takeaways/how-to-update-paginated-data-with-the-android-paging-3-library-ef2d8581e77f

Paging3는 PagingLibrary의 가장 최근 버전이다.
해당 라이브러리는 유저로 하여금 Endpoint가 어디인지 알아서 체크해주고 자동으로 데이터를 로딩해준다.
Room을 사용하든 API , database에서 바로 받아오는 데이터든 pagingsource를 통하므로 상관없다.

페이징 라이브러리의 문제점은 data를 수정하고자 할때 발생한다.

The PagingDataAdapter

paged Data를 보여주기 위해서는 RecyclerView를 상속받은 PagingDataAdapter를 사용해야 한다.
그 말은 즉 PagingDataAdapter에 의존해야 한다는 말이 된다.

RecyclerView.Adapter나 ListAdapter와는 다르게 현재 가지고있는 아이템들이나 보여지고있는 아이템들에 대한 접근할 수 있는 방식이 없다.
따라서 현재 가지고있는 아이템들에 대해서 업데이트를 조작하려고 한다면 어려움을 겪게 되는 것이다.


A practical paging example

Update를 위한 간단한 예시

시나리오

동물원의 사육사가 되어서 관리를 하는 입장이라고 생각해보자.
먼저 동물을 리스트에 보여주고 관리하기 위해서 petted라는 마크를 달려고 한다.
여기에서 문제점은 버튼의 visible을 결정할 때 PagingData를 refresh하거나 API호출을 다시 하지 않고 데이터를 업데이트 할수 있는가? 이다.

data class Animal (
    val name : String,
    var petted : Boolean
)



**Manipulating the paged data**

RecyclerView.Adapter 또는 ListAdapter에서 하는 것처럼 현재 목록에 직접 액세스하고 업데이트할 수 없기 때문에 대안을 사용해야 합니다.

PagingSource로부터 받는 PagingData는 페이지가 매겨진 스냅샷으로 표시됩니다. 즉, 우리는 이 스냅샷에 액세스하여 쿼리된 데이터를 조작할 수 있습니다.

PagingConfig을 통하여 한 페이지당 데이터 개수를 정할 수 있다.

아마도 왜 위의 Animal 데이터 클래스의 petted가 가변(var)으로 선언되는지 궁금했을 것이다.
스냅샷 사용의 절충안은 업데이트할 수 있으려면 데이터 모델을 변경할 수 있어야 한다는 것이다.

따라서 Animal 클래스의 patted 변수를 val이 아닌 var로 선언하는 것이 중요합니다.

Model 을 변경할 수 있다면 우리는 데이터를 조작 할 수 있습니다.

현재 스냅샷에 액세스하려면, PagingDataAdapter의 snapshot() 함수를 호출합니다. 이 함수는 ItemSnapshotList를 반환합니다. 우리 경우의 유형은 물론 Animal Class이다.

class AnimalPagingAdapter(
    private val onAnimalPetted: (Animal) -> Unit
) : PagingDataAdapter<Affirmation, RecyclerView.ViewHolder>(AnimalDiffUtil()) {

// Your PagingAdapter implementation

    inner class RandomAffirmationViewHolder(private val binding: AnimalItemBinding) : RecyclerView.ViewHolder(binding.root) {
        fun bind(animal: Animal) {
            binding.name = animal.name
            binding.pettedButton.isVisible = !animal.petted
            binding.pettedCheckedImageView.isVisible = animal.petted
            
            binding.pettedButton.setOnClickListener {
                onAnimalPetted(animal)
                val snapshotAnimal = this@AnimalPagingAdapter.snapshot().firstOrNull { snapshotAnimal ->
                    snapshotAnimal.name == animal.name
                }
                
                if(snapshotAnimal != null) {
                  snapshotAnimal.petted = true
                  this@AnimalPagingAdapter.notifyDataSetChanged()
                }
            }
        }
    }
}

결론

PaigngAdapter를 사용하게 되면 List를 통제하는데 있어서 어려움을 겪을 수 밖에 없다.
왜냐하면 PagingAdapter는 DataModel만 제출하며 PagingSource를 통해 Snapshot개념으로 데이터를 어댑터에 제공하기 때문이다. 따라서 데이터 모델에 가변 변수를 설정하고 특정 이벤트에 따라 변수를 바꿔줍니다.
바뀐 변수에 따라서 아이템의 모습을 변경시켜주는 방법을 사용한다면 API호출없이 데이터를 변경해 줄 수 있습니다.

profile
러닝커브를 따라서 등반중입니다.

2개의 댓글

comment-user-thumbnail
2022년 2월 22일

잘 보고 갑니다. 짱이에여 ㅎㅎ

1개의 답글