این راهنما مبتنی بر نمای کلی کتابخانه صفحهبندی است و در مورد چگونگی سفارشیسازی راهحل بارگذاری داده برنامهتان برای رفع نیازهای معماری برنامهتان بحث میکند.
یک لیست قابل مشاهده بسازید
به طور معمول، کد UI شما یک شی LiveData<PagedList>
(یا اگر از RxJava2 استفاده می کنید، یک شیء Flowable<PagedList>
یا Observable<PagedList>
) را مشاهده می کند که در ViewModel
برنامه شما قرار دارد. این شیء قابل مشاهده ارتباطی بین نمایش و محتوای داده های لیست برنامه شما ایجاد می کند.
برای ایجاد یکی از این اشیاء PagedList
قابل مشاهده، یک نمونه از DataSource.Factory
را به یک شی LivePagedListBuilder
یا RxPagedListBuilder
ارسال کنید. یک شی DataSource
صفحات را برای یک PagedList
بارگیری می کند. کلاس کارخانه نمونه های جدیدی از PagedList
را در پاسخ به به روز رسانی محتوا، مانند باطل شدن جدول پایگاه داده و به روز رسانی شبکه ایجاد می کند. کتابخانه تداوم اتاق می تواند اشیاء DataSource.Factory
را برای شما فراهم کند، یا می توانید خود را بسازید .
قطعه کد زیر نحوه ایجاد یک نمونه جدید از LiveData<PagedList>
را در کلاس ViewModel
برنامه خود با استفاده از قابلیتهای Room's DataSource.Factory
-building نشان میدهد:
کاتلین
@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> }
جاوا
@Dao public interface ConcertDao { // The Integer type parameter tells Room to use a PositionalDataSource // object, with position-based loading under the hood. @Query("SELECT * FROM concerts ORDER BY date DESC") DataSource.Factory<Integer, Concert> concertsByDate(); }
کاتلین
// The Int type argument corresponds to a PositionalDataSource object. val myConcertDataSource : DataSource.Factory<Int, Concert> = concertDao.concertsByDate() val concertList = myConcertDataSource.toLiveData(pageSize = 50)
جاوا
// The Integer type argument corresponds to a PositionalDataSource object. DataSource.Factory<Integer, Concert> myConcertDataSource = concertDao.concertsByDate(); LiveData<PagedList<Concert>> concertList = LivePagedListBuilder(myConcertDataSource, /* page size */ 50).build();
پیکربندی صفحه بندی خود را تعریف کنید
برای پیکربندی بیشتر LiveData<PagedList>
برای موارد پیشرفته، میتوانید پیکربندی صفحهبندی خود را نیز تعریف کنید. به طور خاص، می توانید ویژگی های زیر را تعریف کنید:
- اندازه صفحه : تعداد موارد موجود در هر صفحه.
- فاصله از پیش واکشی : با توجه به آخرین مورد قابل مشاهده در رابط کاربری برنامه، تعداد مواردی فراتر از آخرین موردی که کتابخانه صفحهبندی باید از قبل تلاش کند واکشی کند. این مقدار باید چندین برابر بزرگتر از اندازه صفحه باشد.
- حضور جایبان : تعیین میکند که آیا UI برای آیتمهای فهرستی که هنوز بارگیری نشدهاند، متغیرهایی را نمایش میدهد یا خیر. برای بحث در مورد مزایا و معایب استفاده از متغیرهایی، یاد بگیرید که چگونه متغیرهایی را در رابط کاربری خود ارائه کنید .
اگر میخواهید کنترل بیشتری روی زمانی که کتابخانه صفحهبندی فهرستی را از پایگاه داده برنامه شما بارگیری میکند، یک شی Executor
سفارشی را به LivePagedListBuilder
ارسال کنید، همانطور که در قطعه کد زیر نشان داده شده است:
کاتلین
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 )
جاوا
PagedList.Config myPagingConfig = new PagedList.Config.Builder() .setPageSize(50) .setPrefetchDistance(150) .setEnablePlaceholders(true) .build(); // The Integer type argument corresponds to a PositionalDataSource object. DataSource.Factory<Integer, Concert> myConcertDataSource = concertDao.concertsByDate(); LiveData<PagedList<Concert>> concertList = new LivePagedListBuilder<>(myConcertDataSource, myPagingConfig) .setFetchExecutor(myExecutor) .build();
نوع منبع داده صحیح را انتخاب کنید
مهم است که به منبع داده ای که به بهترین شکل ساختار داده منبع شما را مدیریت می کند وصل شوید:
- اگر صفحاتی که بارگیری می کنید کلیدهای بعدی/قبلی را جاسازی می کنند، از
PageKeyedDataSource
استفاده کنید. به عنوان مثال، اگر پستهای رسانههای اجتماعی را از شبکه دریافت میکنید، ممکن است لازم باشد یک نشانهnextPage
را از یک بار به بار بعدی منتقل کنید. - اگر نیاز به استفاده از داده های مورد N برای واکشی مورد N+1 دارید، از
ItemKeyedDataSource
استفاده کنید. برای مثال، اگر نظرات رشتهای را برای یک برنامه گفتگو واکشی میکنید، ممکن است لازم باشد شناسه آخرین نظر را برای دریافت محتوای نظر بعدی ارسال کنید. - اگر نیاز به واکشی صفحات داده از هر مکانی که در فروشگاه داده خود انتخاب می کنید، از
PositionalDataSource
استفاده کنید. این کلاس از درخواست مجموعه ای از اقلام داده که از هر مکانی که انتخاب می کنید شروع می شود پشتیبانی می کند. به عنوان مثال، درخواست ممکن است 50 مورد داده را که با مکان 1500 شروع می شوند، برگرداند.
در صورت نامعتبر بودن داده ها اطلاع دهید
هنگام استفاده از کتابخانه صفحهبندی، این وظیفه لایه داده است که وقتی جدول یا ردیفی کهنه شده است، سایر لایههای برنامه شما را مطلع کند. برای انجام این کار، از کلاس DataSource
که برای برنامه خود انتخاب کرده اید، invalidate()
را فراخوانی کنید.
منابع داده خود را بسازید
اگر از یک راه حل سفارشی داده محلی استفاده می کنید، یا اگر داده ها را مستقیماً از یک شبکه بارگیری می کنید، می توانید یکی از زیر کلاس های DataSource
را پیاده سازی کنید. قطعه کد زیر منبع داده ای را نشان می دهد که از زمان شروع کنسرت مشخص شده است:
کاتلین
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) } }
جاوا
public class ConcertTimeDataSource extends ItemKeyedDataSource<Date, Concert> { @NonNull @Override public Date getKey(@NonNull Concert item) { return item.getStartTime(); } @Override public void loadInitial(@NonNull LoadInitialParams<Date> params, @NonNull LoadInitialCallback<Concert> callback) { List<Concert> items = fetchItems(params.key, params.requestedLoadSize); callback.onResult(items); } @Override public void loadAfter(@NonNull LoadParams<Date> params, @NonNull LoadCallback<Concert> callback) { List<Concert> items = fetchItemsAfter(params.key, params.requestedLoadSize); callback.onResult(items); }
سپس میتوانید این دادههای سفارشیشده را با ایجاد یک زیرکلاس مشخص از DataSource.Factory
در اشیاء PagedList
بارگیری کنید. قطعه کد زیر نحوه تولید نمونه های جدید از منبع داده سفارشی تعریف شده در قطعه کد قبلی را نشان می دهد:
کاتلین
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 } }
جاوا
public class ConcertTimeDataSourceFactory extends DataSource.Factory<Date, Concert> { private MutableLiveData<ConcertTimeDataSource> sourceLiveData = new MutableLiveData<>(); private ConcertDataSource latestSource; @Override public DataSource<Date, Concert> create() { latestSource = new ConcertTimeDataSource(); sourceLiveData.postValue(latestSource); return latestSource; } }
نحوه عملکرد به روز رسانی محتوا را در نظر بگیرید
همانطور که اشیاء PagedList
قابل مشاهده را می سازید، نحوه عملکرد به روز رسانی محتوا را در نظر بگیرید. اگر دادهها را مستقیماً از پایگاه داده اتاق بارگیری میکنید، بهروزرسانیها بهطور خودکار به رابط کاربری برنامه شما منتقل میشوند.
هنگام استفاده از یک 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() }
جاوا
public class ConcertActivity extends AppCompatActivity { @Override public void onCreate(@Nullable Bundle savedInstanceState) { // ... viewModel.getRefreshState() .observe(this, new Observer<NetworkState>() { // Shows one possible way of triggering a refresh operation. @Override public void onChanged(@Nullable MyNetworkState networkState) { swipeRefreshLayout.isRefreshing = networkState == MyNetworkState.LOADING; } }; swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshListener() { @Override public void onRefresh() { viewModel.invalidateDataSource(); } }); } } public class ConcertTimeViewModel extends ViewModel { private LiveData<PagedList<Concert>> concertList; private DataSource<Date, Concert> mostRecentDataSource; public ConcertTimeViewModel(Date firstConcertStartTime) { ConcertTimeDataSourceFactory dataSourceFactory = new ConcertTimeDataSourceFactory(firstConcertStartTime); mostRecentDataSource = dataSourceFactory.create(); concertList = new LivePagedListBuilder<>(dataSourceFactory, 50) .setFetchExecutor(myExecutor) .build(); } public void invalidateDataSource() { mostRecentDataSource.invalidate(); } }
ارائه نقشه داده ها
کتابخانه صفحهبندی از تبدیلهای مبتنی بر آیتم و مبتنی بر صفحه آیتمهای بارگیریشده توسط DataSource
پشتیبانی میکند.
در قطعه کد زیر، ترکیبی از نام کنسرت و تاریخ کنسرت به یک رشته منفرد که هم نام و هم تاریخ را در خود دارد نگاشت میشود:
کاتلین
class ConcertViewModel : ViewModel() { val concertDescriptions : LiveData<PagedList<String>> init { val concerts = database.allConcertsFactory() .map { "${it.name} - ${it.date}" } .toLiveData(pageSize = 50) } }
جاوا
public class ConcertViewModel extends ViewModel { private LiveData<PagedList<String>> concertDescriptions; public ConcertViewModel(MyDatabase database) { DataSource.Factory<Integer, Concert> factory = database.allConcertsFactory().map(concert -> concert.getName() + "-" + concert.getDate()); concertDescriptions = new LivePagedListBuilder<>( factory, /* page size */ 50).build(); } }
این می تواند مفید باشد اگر بخواهید موارد را پس از بارگیری بسته بندی، تبدیل یا آماده کنید. از آنجایی که این کار بر روی مجری واکشی انجام می شود، می توانید کارهای بالقوه گرانی مانند خواندن از روی دیسک یا جستجو در یک پایگاه داده جداگانه انجام دهید.
بازخورد ارائه دهید
نظرات و ایده های خود را از طریق این منابع با ما در میان بگذارید:
- ردیاب مشکل
- مشکلات را گزارش کنید تا بتوانیم اشکالات را برطرف کنیم.
منابع اضافی
برای کسب اطلاعات بیشتر در مورد کتابخانه صفحه بندی، به منابع زیر مراجعه کنید.
نمونه ها
Codelabs
ویدیوها
- Android Jetpack: لیست های بی نهایت را با RecyclerView و Paging مدیریت کنید (Google I/O '18)
- Android Jetpack: پیجینگ
برای شما توصیه می شود
- توجه: متن پیوند زمانی که جاوا اسکریپت خاموش است نمایش داده می شود
- مهاجرت به صفحه 3
- نمای کلی کتابخانه Paging 2
- نمایش لیست های صفحه بندی شده