ไลบรารีการแบ่งหน้าจะติดตามสถานะของคำขอโหลดสำหรับข้อมูลที่แบ่งหน้าและเปิดเผย
ผ่านชั้นเรียน LoadState
แอปของคุณสามารถลงทะเบียน Listener ด้วย
PagingDataAdapter
ถึง
รับข้อมูลเกี่ยวกับสถานะปัจจุบันของ และอัปเดต UI ให้สอดคล้องกัน เหล่านี้
สถานะจะแสดงจากอะแดปเตอร์เนื่องจากซิงโครนัสกับ UI
ซึ่งหมายความว่า Listener ของคุณจะได้รับการอัปเดตเมื่อการโหลดหน้าเว็บ
ที่ใช้กับ UI แล้ว
สัญญาณ LoadState
แต่ละรายการมีไว้สำหรับแต่ละสัญญาณ
LoadType
และประเภทแหล่งข้อมูล
(PagingSource
หรือ
RemoteMediator
)
CombinedLoadStates
ออบเจ็กต์ที่ Listener ระบุไว้ให้ข้อมูลเกี่ยวกับสถานะการโหลด
จากสัญญาณทั้งหมดเหล่านี้ คุณสามารถใช้ข้อมูลโดยละเอียดนี้เพื่อแสดง
สัญญาณบอกสถานะการโหลดที่เหมาะสมให้กับผู้ใช้
กำลังโหลดสถานะ
ไลบรารีการแบ่งหน้าจะแสดงสถานะการโหลดเพื่อใช้ใน UI ผ่านทาง
ออบเจ็กต์ LoadState
รายการ ออบเจ็กต์ LoadState
รายการมี 1 ใน 3 รูปแบบขึ้นอยู่กับ
สถานะการโหลดปัจจุบัน:
- หากไม่มีการดำเนินการโหลดที่ทำงานอยู่และไม่มีข้อผิดพลาด
LoadState
จะเป็นLoadState.NotLoading
ออบเจ็กต์ คลาสย่อยนี้ยังรวมถึงendOfPaginationReached
ซึ่งระบุว่าถึงส่วนท้ายของหน้าแล้วหรือไม่ - หากมีการโหลดที่ใช้งานอยู่
LoadState
จะเป็นLoadState.Loading
ออบเจ็กต์ - หากมีข้อผิดพลาด
LoadState
จะเป็นLoadState.Error
การใช้ LoadState
ใน UI มี 2 วิธี ได้แก่ การใช้ Listener หรือการใช้
อะแดปเตอร์รายการพิเศษเพื่อแสดงสถานะการโหลดโดยตรงใน
RecyclerView
รายการ
เข้าถึงสถานะการโหลดด้วย Listener
หากต้องการดูสถานะการโหลดสำหรับการใช้งานทั่วไปใน UI ให้ใช้
loadStateFlow
หรือ
addLoadStateListener()
ที่ได้รับจาก PagingDataAdapter
กลไกเหล่านี้ช่วยให้เข้าถึง
ออบเจ็กต์ CombinedLoadStates
ที่มีข้อมูลเกี่ยวกับ LoadState
สำหรับการโหลดแต่ละประเภท
ในตัวอย่างต่อไปนี้ PagingDataAdapter
แสดง UI ที่แตกต่างกัน
ที่ขึ้นอยู่กับสถานะปัจจุบันของการโหลดการรีเฟรช
Kotlin
// Activities can use lifecycleScope directly, but Fragments should instead use // viewLifecycleOwner.lifecycleScope. lifecycleScope.launch { pagingAdapter.loadStateFlow.collectLatest { loadStates -> progressBar.isVisible = loadStates.refresh is LoadState.Loading retry.isVisible = loadState.refresh !is LoadState.Loading errorMsg.isVisible = loadState.refresh is LoadState.Error } }
Java
pagingAdapter.addLoadStateListener(loadStates -> { progressBar.setVisibility(loadStates.refresh instanceof LoadState.Loading ? View.VISIBLE : View.GONE); retry.setVisibility(loadStates.refresh instanceof LoadState.Loading ? View.GONE : View.VISIBLE); errorMsg.setVisibility(loadStates.refresh instanceof LoadState.Error ? View.VISIBLE : View.GONE); });
Java
pagingAdapter.addLoadStateListener(loadStates -> { progressBar.setVisibility(loadStates.refresh instanceof LoadState.Loading ? View.VISIBLE : View.GONE); retry.setVisibility(loadStates.refresh instanceof LoadState.Loading ? View.GONE : View.VISIBLE); errorMsg.setVisibility(loadStates.refresh instanceof LoadState.Error ? View.VISIBLE : View.GONE); });
ดูข้อมูลเพิ่มเติมเกี่ยวกับ CombinedLoadStates
ได้ที่เข้าถึงการโหลดเพิ่มเติม
ข้อมูลของรัฐ
แสดงสถานะการโหลดด้วยอะแดปเตอร์
ไลบรารีการสร้างหน้าจะมีอะแดปเตอร์รายการอีกรายการหนึ่งที่ชื่อ
LoadStateAdapter
สำหรับ
วัตถุประสงค์ของการแสดงสถานะการโหลดโดยตรงในรายการที่แสดงแบบแบ่งหน้า
อะแดปเตอร์นี้ให้การเข้าถึงสถานะการโหลดปัจจุบันของรายการ ซึ่ง
เพื่อส่งผ่านไปยังมุมมองที่กำหนดเองที่แสดงข้อมูลนั้น
ก่อนอื่น ให้สร้างคลาสผู้ถือครองข้อมูลพร็อพเพอร์ตี้ที่เก็บการอ้างอิงถึงการโหลดและข้อผิดพลาด
บนหน้าจอ สร้างฟังก์ชัน bind()
ที่ยอมรับ LoadState
เป็น
พารามิเตอร์ ฟังก์ชันนี้ควรสลับการแสดงมุมมองตามการโหลด
พารามิเตอร์สถานะ:
Kotlin
class LoadStateViewHolder( parent: ViewGroup, retry: () -> Unit ) : RecyclerView.ViewHolder( LayoutInflater.from(parent.context) .inflate(R.layout.load_state_item, parent, false) ) { private val binding = LoadStateItemBinding.bind(itemView) private val progressBar: ProgressBar = binding.progressBar private val errorMsg: TextView = binding.errorMsg private val retry: Button = binding.retryButton .also { it.setOnClickListener { retry() } } fun bind(loadState: LoadState) { if (loadState is LoadState.Error) { errorMsg.text = loadState.error.localizedMessage } progressBar.isVisible = loadState is LoadState.Loading retry.isVisible = loadState is LoadState.Error errorMsg.isVisible = loadState is LoadState.Error } }
Java
class LoadStateViewHolder extends RecyclerView.ViewHolder { private ProgressBar mProgressBar; private TextView mErrorMsg; private Button mRetry; LoadStateViewHolder( @NonNull ViewGroup parent, @NonNull View.OnClickListener retryCallback) { super(LayoutInflater.from(parent.getContext()) .inflate(R.layout.load_state_item, parent, false)); LoadStateItemBinding binding = LoadStateItemBinding.bind(itemView); mProgressBar = binding.progressBar; mErrorMsg = binding.errorMsg; mRetry = binding.retryButton; } public void bind(LoadState loadState) { if (loadState instanceof LoadState.Error) { LoadState.Error loadStateError = (LoadState.Error) loadState; mErrorMsg.setText(loadStateError.getError().getLocalizedMessage()); } mProgressBar.setVisibility(loadState instanceof LoadState.Loading ? View.VISIBLE : View.GONE); mRetry.setVisibility(loadState instanceof LoadState.Error ? View.VISIBLE : View.GONE); mErrorMsg.setVisibility(loadState instanceof LoadState.Error ? View.VISIBLE : View.GONE); } }
Java
class LoadStateViewHolder extends RecyclerView.ViewHolder { private ProgressBar mProgressBar; private TextView mErrorMsg; private Button mRetry; LoadStateViewHolder( @NonNull ViewGroup parent, @NonNull View.OnClickListener retryCallback) { super(LayoutInflater.from(parent.getContext()) .inflate(R.layout.load_state_item, parent, false)); LoadStateItemBinding binding = LoadStateItemBinding.bind(itemView); mProgressBar = binding.progressBar; mErrorMsg = binding.errorMsg; mRetry = binding.retryButton; } public void bind(LoadState loadState) { if (loadState instanceof LoadState.Error) { LoadState.Error loadStateError = (LoadState.Error) loadState; mErrorMsg.setText(loadStateError.getError().getLocalizedMessage()); } mProgressBar.setVisibility(loadState instanceof LoadState.Loading ? View.VISIBLE : View.GONE); mRetry.setVisibility(loadState instanceof LoadState.Error ? View.VISIBLE : View.GONE); mErrorMsg.setVisibility(loadState instanceof LoadState.Error ? View.VISIBLE : View.GONE); } }
จากนั้นให้สร้างคลาสที่ใช้งาน LoadStateAdapter
และกำหนด
onCreateViewHolder()
และ
onBindViewHolder()
วิธีการเหล่านี้จะสร้างอินสแตนซ์ของตัวยึดตำแหน่งมุมมองที่กำหนดเองและเชื่อมโยง
สถานะการโหลดที่เกี่ยวข้อง
Kotlin
// Adapter that displays a loading spinner when // state is LoadState.Loading, and an error message and retry // button when state is LoadState.Error. class ExampleLoadStateAdapter( private val retry: () -> Unit ) : LoadStateAdapter<LoadStateViewHolder>() { override fun onCreateViewHolder( parent: ViewGroup, loadState: LoadState ) = LoadStateViewHolder(parent, retry) override fun onBindViewHolder( holder: LoadStateViewHolder, loadState: LoadState ) = holder.bind(loadState) }
Java
// Adapter that displays a loading spinner when // state is LoadState.Loading, and an error message and retry // button when state is LoadState.Error. class ExampleLoadStateAdapter extends LoadStateAdapter<LoadStateViewHolder> { private View.OnClickListener mRetryCallback; ExampleLoadStateAdapter(View.OnClickListener retryCallback) { mRetryCallback = retryCallback; } @NotNull @Override public LoadStateViewHolder onCreateViewHolder(@NotNull ViewGroup parent, @NotNull LoadState loadState) { return new LoadStateViewHolder(parent, mRetryCallback); } @Override public void onBindViewHolder(@NotNull LoadStateViewHolder holder, @NotNull LoadState loadState) { holder.bind(loadState); } }
Java
// Adapter that displays a loading spinner when // state is LoadState.Loading, and an error message and retry // button when state is LoadState.Error. class ExampleLoadStateAdapter extends LoadStateAdapter<LoadStateViewHolder> { private View.OnClickListener mRetryCallback; ExampleLoadStateAdapter(View.OnClickListener retryCallback) { mRetryCallback = retryCallback; } @NotNull @Override public LoadStateViewHolder onCreateViewHolder(@NotNull ViewGroup parent, @NotNull LoadState loadState) { return new LoadStateViewHolder(parent, mRetryCallback); } @Override public void onBindViewHolder(@NotNull LoadStateViewHolder holder, @NotNull LoadState loadState) { holder.bind(loadState); } }
แสดงสถานะการโหลดเป็นส่วนหัวหรือส่วนท้าย
หากต้องการแสดงความคืบหน้าในการโหลดในส่วนหัวและส่วนท้าย ให้เรียกเมธอด
withLoadStateHeaderAndFooter()
จากออบเจ็กต์ PagingDataAdapter
ของคุณ:
Kotlin
pagingAdapter .withLoadStateHeaderAndFooter( header = ExampleLoadStateAdapter(adapter::retry), footer = ExampleLoadStateAdapter(adapter::retry) )
Java
pagingAdapter .withLoadStateHeaderAndFooter( new ExampleLoadStateAdapter(pagingAdapter::retry), new ExampleLoadStateAdapter(pagingAdapter::retry));
Java
pagingAdapter .withLoadStateHeaderAndFooter( new ExampleLoadStateAdapter(pagingAdapter::retry), new ExampleLoadStateAdapter(pagingAdapter::retry));
คุณสามารถโทรหา
withLoadStateHeader()
หรือ
withLoadStateFooter()
หากคุณต้องการให้รายการ RecyclerView
แสดงสถานะการโหลดเฉพาะใน
หรือเฉพาะในส่วนท้าย
เข้าถึงข้อมูลสถานะการโหลดเพิ่มเติม
ออบเจ็กต์ CombinedLoadStates
จาก PagingDataAdapter
ให้ข้อมูลเกี่ยวกับ
สถานะการโหลดสำหรับการใช้งาน PagingSource
ของคุณ และยังสำหรับ
การติดตั้งใช้งาน RemoteMediator
หากมี
เพื่อความสะดวก คุณสามารถใช้
refresh
append
และ
prepend
พร็อพเพอร์ตี้จาก CombinedLoadStates
เพื่อเข้าถึงออบเจ็กต์ LoadState
สำหรับ
ประเภทการโหลดที่เหมาะสม โดยทั่วไปแล้ว พร็อพเพอร์ตี้เหล่านี้จะยึดตามสถานะการโหลดจาก
การใช้งาน RemoteMediator
หากมี มิฉะนั้นจะมี
สถานะการโหลดที่เหมาะสมจากการใช้งาน PagingSource
หากต้องการทราบรายละเอียดเพิ่มเติม
เกี่ยวกับตรรกะที่สำคัญ โปรดดูเอกสารอ้างอิงสำหรับ
CombinedLoadStates
Kotlin
lifecycleScope.launch { pagingAdapter.loadStateFlow.collectLatest { loadStates -> // Observe refresh load state from RemoteMediator if present, or // from PagingSource otherwise. refreshLoadState: LoadState = loadStates.refresh // Observe prepend load state from RemoteMediator if present, or // from PagingSource otherwise. prependLoadState: LoadState = loadStates.prepend // Observe append load state from RemoteMediator if present, or // from PagingSource otherwise. appendLoadState: LoadState = loadStates.append } }
Java
pagingAdapter.addLoadStateListener(loadStates -> { // Observe refresh load state from RemoteMediator if present, or // from PagingSource otherwise. LoadState refreshLoadState = loadStates.refresh; // Observe prepend load state from RemoteMediator if present, or // from PagingSource otherwise. LoadState prependLoadState = loadStates.prepend; // Observe append load state from RemoteMediator if present, or // from PagingSource otherwise. LoadState appendLoadState = loadStates.append; });
Java
pagingAdapter.addLoadStateListener(loadStates -> { // Observe refresh load state from RemoteMediator if present, or // from PagingSource otherwise. LoadState refreshLoadState = loadStates.refresh; // Observe prepend load state from RemoteMediator if present, or // from PagingSource otherwise. LoadState prependLoadState = loadStates.prepend; // Observe append load state from RemoteMediator if present, or // from PagingSource otherwise. LoadState appendLoadState = loadStates.append; });
อย่างไรก็ตาม โปรดทราบว่าเฉพาะสถานะการโหลด PagingSource
เท่านั้น
เพื่อให้แน่ใจว่าการอัปเดต UI ทำงานพร้อมกัน เนื่องจาก refresh
พร็อพเพอร์ตี้ append
และ prepend
อาจรับสถานะการโหลดจาก
PagingSource
หรือ RemoteMediator
ก็ไม่รับประกันว่าจะเป็น
พร้อมกันพร้อมการอัปเดต UI ซึ่งอาจทำให้เกิดปัญหากับ UI ในตำแหน่งที่การโหลดปรากฏขึ้น
ให้เสร็จก่อนที่จะเพิ่มข้อมูลใหม่ลงใน UI
ด้วยเหตุนี้ ตัวเข้าถึงเพื่ออำนวยความสะดวกจึงทำงานได้ดีในการแสดงโหลด
ในส่วนหัวหรือส่วนท้าย แต่สำหรับกรณีการใช้งานอื่นๆ คุณอาจต้อง
เข้าถึงสถานะการโหลดโดยเฉพาะจาก PagingSource
หรือ
RemoteMediator
CombinedLoadStates
จะมี
source
และ
mediator
เพื่อวัตถุประสงค์นี้ พร็อพเพอร์ตี้เหล่านี้แต่ละรายการจะแสดง
LoadStates
ที่
มีออบเจ็กต์ LoadState
สำหรับ PagingSource
หรือ RemoteMediator
ตามลำดับ
Kotlin
lifecycleScope.launch { pagingAdapter.loadStateFlow.collectLatest { loadStates -> // Directly access the RemoteMediator refresh load state. mediatorRefreshLoadState: LoadState? = loadStates.mediator.refresh // Directly access the RemoteMediator append load state. mediatorAppendLoadState: LoadState? = loadStates.mediator.append // Directly access the RemoteMediator prepend load state. mediatorPrependLoadState: LoadState? = loadStates.mediator.prepend // Directly access the PagingSource refresh load state. sourceRefreshLoadState: LoadState = loadStates.source.refresh // Directly access the PagingSource append load state. sourceAppendLoadState: LoadState = loadStates.source.append // Directly access the PagingSource prepend load state. sourcePrependLoadState: LoadState = loadStates.source.prepend } }
Java
pagingAdapter.addLoadStateListener(loadStates -> { // Directly access the RemoteMediator refresh load state. LoadState mediatorRefreshLoadState = loadStates.mediator.refresh; // Directly access the RemoteMediator append load state. LoadState mediatorAppendLoadState = loadStates.mediator.append; // Directly access the RemoteMediator prepend load state. LoadState mediatorPrependLoadState = loadStates.mediator.prepend; // Directly access the PagingSource refresh load state. LoadState sourceRefreshLoadState = loadStates.source.refresh; // Directly access the PagingSource append load state. LoadState sourceAppendLoadState = loadStates.source.append; // Directly access the PagingSource prepend load state. LoadState sourcePrependLoadState = loadStates.source.prepend; });
Java
pagingAdapter.addLoadStateListener(loadStates -> { // Directly access the RemoteMediator refresh load state. LoadState mediatorRefreshLoadState = loadStates.mediator.refresh; // Directly access the RemoteMediator append load state. LoadState mediatorAppendLoadState = loadStates.mediator.append; // Directly access the RemoteMediator prepend load state. LoadState mediatorPrependLoadState = loadStates.mediator.prepend; // Directly access the PagingSource refresh load state. LoadState sourceRefreshLoadState = loadStates.source.refresh; // Directly access the PagingSource append load state. LoadState sourceAppendLoadState = loadStates.source.append; // Directly access the PagingSource prepend load state. LoadState sourcePrependLoadState = loadStates.source.prepend; });
โอเปอเรเตอร์เชนใน LoadState
เนื่องจากออบเจ็กต์ CombinedLoadStates
ให้สิทธิ์เข้าถึงการเปลี่ยนแปลงทั้งหมดใน
สถานะการโหลด สิ่งสำคัญคือต้องกรองสตรีมสถานะการโหลด โดยอิงตาม
กิจกรรม วิธีนี้ช่วยให้มั่นใจว่าคุณอัปเดต UI ในเวลาที่เหมาะสมเพื่อหลีกเลี่ยง
การกระตุกและการอัปเดต UI ที่ไม่จำเป็น
ตัวอย่างเช่น สมมติว่าคุณต้องการแสดงมุมมองว่างเปล่า แต่หลังจาก
การโหลดข้อมูลเริ่มต้นเสร็จสมบูรณ์ กรณีการใช้งานนี้กำหนดให้คุณต้องยืนยันว่า
เริ่มโหลดการรีเฟรชแล้ว จากนั้นรอให้สถานะ NotLoading
ยืนยันว่า
การรีเฟรชเสร็จสมบูรณ์แล้ว คุณต้องกรองสัญญาณทั้งหมดออก ยกเว้นสัญญาณ
สิ่งที่ต้องมี
Kotlin
lifecycleScope.launchWhenCreated { adapter.loadStateFlow // Only emit when REFRESH LoadState for RemoteMediator changes. .distinctUntilChangedBy { it.refresh } // Only react to cases where REFRESH completes, such as NotLoading. .filter { it.refresh is LoadState.NotLoading } // Scroll to top is synchronous with UI updates, even if remote load was // triggered. .collect { binding.list.scrollToPosition(0) } }
Java
PublishSubject<CombinedLoadStates> subject = PublishSubject.create(); Disposable disposable = subject.distinctUntilChanged(CombinedLoadStates::getRefresh) .filter( combinedLoadStates -> combinedLoadStates.getRefresh() instanceof LoadState.NotLoading) .subscribe(combinedLoadStates -> binding.list.scrollToPosition(0)); pagingAdapter.addLoadStateListener(loadStates -> { subject.onNext(loadStates); });
Java
LiveData<CombinedLoadStates> liveData = new MutableLiveData<>(); LiveData<LoadState> refreshLiveData = Transformations.map(liveData, CombinedLoadStates::getRefresh); LiveData<LoadState> distinctLiveData = Transformations.distinctUntilChanged(refreshLiveData); distinctLiveData.observeForever(loadState -> { if (loadState instanceof LoadState.NotLoading) { binding.list.scrollToPosition(0); } });
ตัวอย่างนี้รอจนกว่าจะอัปเดตสถานะโหลดการรีเฟรช แต่จะมีเฉพาะทริกเกอร์เท่านั้น
เมื่อรัฐคือ NotLoading
การดำเนินการนี้จะช่วยให้มั่นใจว่าการรีเฟรชจากระยะไกลได้
เสร็จก่อนการอัปเดต UI
API ของสตรีมทำให้การดำเนินการประเภทนี้เป็นไปได้ แอปของคุณระบุโหลดได้ เหตุการณ์ที่ต้องการและจัดการข้อมูลใหม่เมื่อตรงกับเกณฑ์ที่เหมาะสม
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- โหลดและแสดงข้อมูลแบบแบ่งหน้า
- หน้าเว็บจากเครือข่ายและฐานข้อมูล
- ภาพรวมของไลบรารีการแบ่งหน้า