페이징된 목록 표시

이 가이드에서는 Paging 라이브러리 개요를 기반으로 특히 정보가 변경될 때 앱의 UI에서 사용자에게 정보 목록을 표시하는 방법을 설명합니다.

뷰 모델에 UI 연결

다음 코드 스니펫에 나와 있는 것처럼 LiveData<PagedList>의 인스턴스를 PagedListAdapter에 연결할 수 있습니다.

Kotlin

class ConcertActivity : AppCompatActivity() {
    private val adapter = ConcertAdapter()

    // Use the 'by viewModels()' Kotlin property delegate
    // from the activity-ktx artifact
    private val viewModel: ConcertViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState);
        viewModel.concerts.observe(this, Observer { adapter.submitList(it) })
    }
}

Java

public class ConcertActivity extends AppCompatActivity {
    private ConcertAdapter adapter = new ConcertAdapter();
    private ConcertViewModel viewModel;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        viewModel = new ViewModelProvider(this).get(ConcertViewModel.class);
        viewModel.concertList.observe(this, adapter::submitList);
    }
}

데이터 소스가 PagedList의 새 인스턴스를 제공하면 활동이 이러한 객체를 어댑터로 보냅니다. PagedListAdapter 구현이 업데이트 계산 방식을 정의하고 페이징과 목록 디핑(Diffing)을 자동으로 처리합니다. 따라서 ViewHolder는 제공된 특정 항목에만 결합되어야 합니다.

Kotlin

class ConcertAdapter() :
        PagedListAdapter<Concert, ConcertViewHolder>(DIFF_CALLBACK) {
    override fun onBindViewHolder(holder: ConcertViewHolder, position: Int) {
        val concert: Concert? = getItem(position)

        // Note that "concert" is a placeholder if it's null.
        holder.bindTo(concert)
    }

    companion object {
        private val DIFF_CALLBACK = ... // See Implement the diffing callback section.
    }
}

Java

public class ConcertAdapter
        extends PagedListAdapter<Concert, ConcertViewHolder> {
    protected ConcertAdapter() {
        super(DIFF_CALLBACK);
    }

    @Override
    public void onBindViewHolder(@NonNull ConcertViewHolder holder,
            int position) {
        Concert concert = getItem(position);

        // Note that "concert" can be null if it's a placeholder.
        holder.bindTo(concert);
    }

    private static DiffUtil.ItemCallback<Concert> DIFF_CALLBACK
            = ... // See Implement the diffing callback section.
}

PagedListAdapterPagedList.Callback 객체를 사용하여 페이지 로드 이벤트를 처리합니다. 사용자가 스크롤하면 PagedListAdapterPagedList.loadAround()를 호출하여 DataSource에서 가져와야 하는 항목에 관한 힌트를 기본 PagedList에 제공합니다.

디핑 콜백 구현

다음 샘플은 관련 객체 필드를 비교하는 areContentsTheSame()의 수동 구현을 나타낸 것입니다.

Kotlin

private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<Concert>() {
    // The ID property identifies when items are the same.
    override fun areItemsTheSame(oldItem: Concert, newItem: Concert) =
            oldItem.id == newItem.id

    // If you use the "==" operator, make sure that the object implements
    // .equals(). Alternatively, write custom data comparison logic here.
    override fun areContentsTheSame(
            oldItem: Concert, newItem: Concert) = oldItem == newItem
}

Java

private static DiffUtil.ItemCallback<Concert> DIFF_CALLBACK =
        new DiffUtil.ItemCallback<Concert>() {

    @Override
    public boolean areItemsTheSame(Concert oldItem, Concert newItem) {
        // The ID property identifies when items are the same.
        return oldItem.getId() == newItem.getId();
    }

    @Override
    public boolean areContentsTheSame(Concert oldItem, Concert newItem) {
        // Don't use the "==" operator here. Either implement and use .equals(),
        // or write custom data comparison logic here.
        return oldItem.equals(newItem);
    }
};

어댑터에는 비교 항목의 정의가 포함되어 있으므로 새 PagedList 객체가 로드되면 어댑터는 이러한 항목의 변경사항을 자동으로 감지합니다. 결과적으로 어댑터는 RecyclerView 객체 내에서 효율적인 항목 애니메이션을 트리거합니다.

다른 어댑터 유형을 사용하여 디핑

자체 어댑터를 제공하는 라이브러리를 사용하는 등 PagedListAdapter에서 상속받지 않기로 선택하더라도 AsyncPagedListDiffer 객체를 직접 사용하여 Paging 라이브러리 어댑터의 디핑 기능을 계속 사용할 수 있습니다.

UI에서 자리표시자 제공

앱이 데이터 가져오기를 완료하기 전에 UI에 목록을 표시하려면 자리표시자 목록 항목을 사용자에게 표시하면 됩니다. PagedList는 데이터가 로드될 때까지 목록 항목 데이터를 null로 표시함으로써 이러한 사례를 처리합니다.

자리표시자 사용 시 다음과 같은 이점이 있습니다.

  • 스크롤바 지원: PagedList가 목록 항목 개수를 PagedListAdapter에 제공합니다. 이 정보를 통해 어댑터는 목록의 전체 크기를 포괄하는 스크롤바를 그릴 수 있습니다. 새 페이지가 로드될 때 목록의 크기가 변경되지 않으므로 스크롤바가 이동하지 않습니다.
  • 로드 중 스피너가 필요하지 않음: 목록 크기가 이미 알려져 있으므로 로드 중인 항목이 더 있음을 사용자에게 알릴 필요가 없습니다. 자리표시자 자체가 이러한 정보를 전달합니다.

그러나 자리표시자에 관한 지원을 추가하기 전에 다음 전제 조건에 유의하세요.

  • 셀 수 있는 데이터 세트 필요: Room 지속성 라이브러리DataSource 인스턴스가 항목 수를 효율적으로 계산할 수 있습니다. 그러나 맞춤 로컬 저장소 솔루션 또는 네트워크 전용 데이터 아키텍처를 사용하고 있다면 데이터 세트를 구성하는 항목 수를 파악하는 것은 리소스를 많이 소모하거나 심지어 불가능할 수도 있습니다.
  • 로드 취소된 항목을 처리하는 데 어댑터 필요: 확장을 위해 목록을 준비하는 데 사용할 어댑터 또는 표시 메커니즘은 null 목록 항목을 처리해야 합니다. 예를 들어 데이터를 ViewHolder에 결합할 경우 로드 취소된 데이터를 보여주기 위한 기본값을 제공해야 합니다.
  • 동일한 크기의 항목 뷰 필요: 소셜 네트워킹 업데이트와 같이 콘텐츠에 따라 목록 항목 크기가 변경될 수 있다면 항목 간 크로스 페이딩은 적합해 보이지 않습니다. 이런 상황에는 자리표시자를 사용하지 않는 것이 좋습니다.

의견 보내기

다음 리소스를 통해 의견을 보내고 아이디어를 공유해 주세요.

Issue Tracker
버그를 수정할 수 있도록 문제를 신고해 주세요.

추가 리소스

Paging 라이브러리에 관해 자세히 알아보려면 다음 리소스를 참고하세요.

샘플

Codelab

동영상