يعتمد هذا الدليل على نظرة عامة على مكتبة الصفحات، حيث يناقش كيفية تخصيص حل تحميل بيانات تطبيقك لتلبية احتياجات بنية تطبيقك.
إنشاء قائمة يمكن قياسها
عادةً ما يلاحظ رمز واجهة المستخدم كائن
LiveData<PagedList>
(أو
كائن RxJava2،
Flowable<PagedList>
أو Observable<PagedList>
)، وهو موجود في ViewModel
لتطبيقك. ويشكّل هذا العنصر الذي يمكن ملاحظته رابطًا بين العرض التقديمي ومحتويات بيانات قائمة تطبيقك.
لإنشاء أحد هذه الكائنات
PagedList
القابلة للملاحظة،
أرسِل مثيل
DataSource.Factory
إلى
كائن LivePagedListBuilder
أو RxPagedListBuilder
. يُحمِّل كائن DataSource
صفحات لـ PagedList
واحد. تنشئ فئة المصنع نُسخًا جديدة من
PagedList
استجابةً لتحديثات المحتوى، مثل عمليات إلغاء صلاحية جدول قاعدة البيانات
وعمليات إعادة تحميل الشبكة. ويمكن أن توفّر لك مكتبة
البقاء في الغرفة عناصر DataSource.Factory
، أو يمكنك إنشاء كائنات خاصة بك.
يوضِّح مقتطف الرمز التالي كيفية إنشاء مثيل جديد من
LiveData<PagedList>
في
فئة ViewModel
لتطبيقك باستخدام
إمكانات إنشاء
DataSource.Factory
في الغرفة:
Kotlin
@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> }
Java
@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(); }
Kotlin
// The Int type argument corresponds to a PositionalDataSource object. val myConcertDataSource : DataSource.Factory<Int, Concert> = concertDao.concertsByDate() val concertList = myConcertDataSource.toLiveData(pageSize = 50)
Java
// 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>
بشكلٍ أكبر للحالات المتقدّمة، يمكنك أيضًا تحديد إعدادات نقل الصفحات الخاصة بك. وعلى وجه الخصوص، يمكنك تعريف السمات التالية:
- حجم الصفحة: عدد العناصر في كل صفحة
- المسافة الجلب المسبق: بالنظر إلى آخر عنصر مرئي في واجهة مستخدم التطبيق، عدد العناصر التي يجب أن تحاول "مكتبة الترحيل" جلبها مقدّمًا بعد هذا العنصر الأخير. يجب أن تكون هذه القيمة أكبر بضع مرات من حجم الصفحة.
- تواجد العناصر النائبة: تحدد ما إذا كانت واجهة المستخدم تعرض عناصر نائبة لعناصر القائمة التي لم ينتهِ تحميلها بعد. لإجراء مناقشة حول مزايا وعيوب استخدام العناصر النائبة، تعرَّف على كيفية توفير العناصر النائبة في واجهة المستخدم.
إذا كنت ترغب في المزيد من التحكم في وقت تحميل "مكتبة تسجيل الصفحات" لقائمة من قاعدة بيانات تطبيقك، مرِّر كائن Executor
مخصَّصًا إلى
LivePagedListBuilder
،
كما هو موضّح في مقتطف الرمز التالي:
Kotlin
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 )
Java
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
من حِمل واحد إلى عملية تحميل لاحقة. - استخدِم
ItemKeyedDataSource
إذا كنت بحاجة إلى استخدام بيانات من العنصر N لجلب العنصر N+1. على سبيل المثال، إذا كنت تجلب تعليقات متسلسلة لتطبيق مناقشة، فقد تحتاج إلى تمرير معرّف التعليق الأخير للحصول على محتويات التعليق التالي. - استخدِم
PositionalDataSource
إذا كنت بحاجة إلى استرجاع صفحات البيانات من أي موقع جغرافي تختاره في متجر البيانات. تتيح هذه الفئة طلب مجموعة من عناصر البيانات بدءًا من أي موقع جغرافي تختاره. على سبيل المثال، قد يعرض الطلب 50 عنصر بيانات يبدأ بالموقع 1500.
إرسال إشعار عندما تكون البيانات غير صالحة
عند استخدام "مكتبة الترحيل"، يرجع الأمر إلى طبقة البيانات في إشعار الطبقات الأخرى من تطبيقك عندما يصبح جدول أو صف قديمين. ولإجراء ذلك، اتصل بالرقم
invalidate()
من الصف
DataSource
الذي اخترته لتطبيقك.
إنشاء مصادر البيانات الخاصة بك
إذا كنت تستخدم حلاً مخصّصًا للبيانات المحلية، أو إذا حمَّلت البيانات مباشرةً من
شبكة، يمكنك تنفيذ إحدى الفئات الفرعية
DataSource
. يعرض مقتطف الرمز التالي مصدر بيانات تم تسجيله قبل وقت بدء حفلة موسيقية:
Kotlin
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) } }
Java
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); }
ويمكنك بعد ذلك تحميل هذه البيانات المخصّصة إلى عناصر PagedList
من خلال إنشاء فئة فرعية ملموسة من
DataSource.Factory
. يوضّح مقتطف الرمز التالي كيفية إنشاء مثيلات جديدة لمصدر البيانات المخصّصة المحدّد في مقتطف الرمز السابق:
Kotlin
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 } }
Java
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
يمكن ملاحظتها، عليك مراعاة آلية عمل تعديلات المحتوى. في حال تحميل البيانات مباشرةً من قاعدة بيانات الغرفة، يتم إرسال تحديثات إلى واجهة مستخدم التطبيق
تلقائيًا.
عند استخدام واجهة برمجة تطبيقات للشبكة المقسّمة على صفحات، يكون عادةً تفاعل المستخدم، مثل "التمرير سريعًا لإعادة التحميل"، بمثابة إشارة لإلغاء صلاحية DataSource
التي استخدمتها مؤخرًا. يمكنك بعد ذلك طلب مثيل جديد لمصدر البيانات هذا. يوضح مقتطف الرمز التالي هذا السلوك:
Kotlin
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() }
Java
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
.
في مقتطف الرمز التالي، يتم تعيين مجموعة من اسم الحفلة الموسيقية وتاريخها في سلسلة واحدة تحتوي على الاسم والتاريخ:
Kotlin
class ConcertViewModel : ViewModel() { val concertDescriptions : LiveData<PagedList<String>> init { val concerts = database.allConcertsFactory() .map { "${it.name} - ${it.date}" } .toLiveData(pageSize = 50) } }
Java
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(); } }
يمكن أن يكون هذا مفيدًا إذا كنت تريد لف العناصر أو تحويلها أو تحضيرها بعد تحميلها. ولأنّ هذا العمل يتم على الجهاز تنفيذ الجلب، يمكنك القيام بأعمال قد تكون مكلّفة، مثل القراءة من القرص أو الاستعلام عن قاعدة بيانات منفصلة.
تقديم ملاحظات
يُرجى مشاركة ملاحظاتك وآرائك معنا من خلال الموارد التالية:
- أداة تتبّع المشاكل
- يمكنك الإبلاغ عن المشاكل حتى نتمكّن من إصلاح الأخطاء.
مراجع إضافية
لمعرفة المزيد حول مكتبة الترحيل، يمكنك الرجوع إلى الموارد التالية.
عيّنات
- نموذج نقل البيانات لمكونات البنية الأساسية لنظام التشغيل Android
- تقسيم البيانات باستخدام نموذج الشبكة
الدروس التطبيقية حول الترميز
الفيديوهات الطويلة
- Android Jetpack: إدارة القوائم اللانهائية باستخدام RecyclerView وPaging (مؤتمر Google I/O لعام 2018)
- Android Jetpack: الانتقال من الصفحات
أفلام مُقترَحة لك
- ملاحظة: يتم عرض نص الرابط عند إيقاف JavaScript.
- نقل البيانات إلى الصفحة 3
- نظرة عامة على مكتبة الصفحة 2
- عرض قوائم مقسّمة إلى صفحات