تم إيقاف برامج التحميل اعتبارًا من الإصدار 9 من نظام Android (المستوى 28 من واجهة برمجة التطبيقات). الخيار الموصى به
عند التعامل مع بيانات التحميل أثناء دورتَي النشاط Activity
وFragment
، يجب استخدام
مجموعة من عناصر ViewModel
وLiveData
عرض النماذج التي تعاني من تغييرات التهيئة، مثل الرافعات، ولكن مع
رموز معيارية أقل. يوفّر LiveData
طريقة لتحميل البيانات التي يمكنك إعادة استخدامها مع مراعاة مراحل النشاط.
نماذج عرض متعددة. يمكنك أيضًا دمج LiveData
باستخدام
MediatorLiveData
وأي طلبات بحث يمكن ملاحظتها، مثل تلك الواردة من
قاعدة بيانات الغرفة، يمكن استخدامها لرصد التغييرات
للبيانات.
يتوفّر ViewModel
وLiveData
أيضًا في الحالات التي لا يمكنك فيها الوصول إلى الخدمة.
إلى LoaderManager
، كما هو الحال في
Service
يتيح لك استخدام الاثنين في
طريقة سهلة للوصول إلى البيانات التي يحتاجها تطبيقك دون الحاجة إلى التعامل مع واجهة المستخدم
دورة حياة المنتج. لمزيد من المعلومات عن "LiveData
"، يُرجى الاطّلاع على
نظرة عامة على "LiveData
" لمزيد من المعلومات حول
ViewModel
، يمكنك الاطّلاع على نظرة عامة على ViewModel
.
تتيح لك Loader API تحميل البيانات من
أداة توفير المحتوى
أو مصدر بيانات آخر للعرض في FragmentActivity
أو Fragment
.
وبدون برامج التحميل، تتضمن بعض المشكلات التي قد تواجهها ما يلي:
- إذا استرجعت البيانات مباشرةً في النشاط أو الجزء، سيعني المستخدمون تعاني من نقص في سرعة الاستجابة بسبب الأداء البطيء المحتمل من مؤشر ترابط واجهة المستخدم.
- إذا جلبت البيانات من سلسلة محادثات أخرى، ربما باستخدام
AsyncTask
، فأنت مسؤول عن إدارة سلسلة المحادثات هذه وسلسلة واجهة المستخدم من خلال أنشطة متنوعة أو أحداث مراحل نشاط مجزأة، مثلonDestroy()
وتغييرات الإعدادات.
تحل المحمّلات هذه المشاكل وتتضمن مزايا أخرى:
- تعمل برامج التحميل على سلاسل محادثات منفصلة لمنع واجهة المستخدم البطيئة أو غير المستجيبة.
- تبسّط عمليات التحميل إدارة سلاسل المحادثات من خلال توفير طرق معاودة الاتصال عند وقوع الأحداث حدوثها.
- تظل برامج التحميل تحتفظ بالنتائج وتخزّنها في ذاكرة التخزين المؤقت في جميع تغييرات الإعدادات لمنعها. طلبات بحث مكررة.
- يمكن للقائمين بالتحميل تنفيذ أداة مراقبة لمراقبة التغييرات في العنصر الأساسي
ومصدرها. على سبيل المثال، يتم
CursorLoader
تلقائيًا لتسجيلContentObserver
لتشغيل إعادة التحميل عند تغيير البيانات.
ملخّص Loader API
هناك العديد من الفئات والواجهات التي قد يتم تضمينها عند استخدام القائم بالتحميل في أحد التطبيقات. وقد تم تلخيصها في الجدول التالي:
الصف/الواجهة | الوصف |
---|---|
LoaderManager |
تمثّل هذه السمة فئة مجردة مرتبطة بسمة FragmentActivity أو
Fragment لإدارة واحد أو أكثر
Loader مثال لا يوجد سوى
LoaderManager لكل نشاط أو جزء، ولكن
بإمكان LoaderManager إدارة برامج تحميل متعددة.
للحصول على لبدء تحميل البيانات من أداة تحميل، يمكنك استدعاء أحد الإجراءين
|
LoaderManager.LoaderCallbacks |
تحتوي هذه الواجهة على طرق معاودة الاتصال التي يتم استدعاؤها عند
أحداث القائم بالتحميل. تحدِّد الواجهة ثلاث طرق لمعاودة الاتصال:
initLoader() أو
restartLoader()
|
Loader |
وتنفّذ المحمّلات تحميل البيانات. هذه الفئة مجردة وتخدم
باعتبارها الفئة الأساسية لجميع القائمات بالتحميل. يمكنك إنشاء فئة فرعية
Loader أو استخدام أيّ من الميزات المضمَّنة التالية
لتبسيط التنفيذ:
|
توضح لك الأقسام التالية كيفية استخدام هذه الفئات والواجهات في التطبيق.
استخدام برامج التحميل في أحد التطبيقات
يوضّح هذا القسم كيفية استخدام برامج التحميل في أحد تطبيقات Android. إنّ عادةً ما يتضمن التطبيق الذي يستخدم أدوات التحميل ما يلي:
FragmentActivity
أوFragment
- تمثّل هذه السمة مثيلاً للسمة
LoaderManager
. CursorLoader
لتحميل البيانات التي تم نسخها احتياطيًا من خلالContentProvider
. يمكنك بدلاً من ذلك تنفيذ فئتك الفرعية منLoader
أوAsyncTaskLoader
إلى تحميل البيانات من مصدر آخر.- عملية تنفيذ
LoaderManager.LoaderCallbacks
. وهي المكان الذي تنشئ فيه برامج تحميل جديدة وتدير مراجعك الحالية الشركات الأخرى. - طريقة لعرض بيانات برنامج التحميل، مثل
SimpleCursorAdapter
. - مصدر بيانات، مثل
ContentProvider
، عند استخدامCursorLoader
بدء التحميل
يدير LoaderManager
حدثًا واحدًا أو أكثر من أحداث Loader
ضمن FragmentActivity
أو
Fragment
ويتم توفير سمة LoaderManager
واحدة فقط لكل نشاط أو جزء.
أنت عادةً
يجب إعداد Loader
ضمن طريقة onCreate()
للنشاط أو دالة الجزء
طريقة onCreate()
إِنْتَ
قم بذلك على النحو التالي:
Kotlin
supportLoaderManager.initLoader(0, null, this)
Java
// Prepare the loader. Either re-connect with an existing one, // or start a new one. getSupportLoaderManager().initLoader(0, null, this);
تستخدم الطريقة initLoader()
المعلمات التالية:
- معرّف فريد يحدّد القائم بالتحميل. في هذا المثال، يكون رقم التعريف هو
0
. - الوسيطات الاختيارية التي سيتم توفيرها لبرنامج التحميل على
البناء (
null
في هذا المثال). - عملية تنفيذ
LoaderManager.LoaderCallbacks
التي طلباتLoaderManager
للإبلاغ عن أحداث أداة التحميل. في هذه الدورة، سبيل المثال، تنفّذ الفئة المحلية واجهةLoaderManager.LoaderCallbacks
، لذا فإنها تمرر مرجعًا إلى نفسه،this
.
يضمن طلب initLoader()
أن يقوم برنامج التحميل
نشط ونشط. له نتيجتان محتملتان:
- إذا كانت أداة التحميل التي تم تحديدها بواسطة رقم التعريف موجودة من قبل، يتم استخدام آخر برنامج تحميل تم إنشاؤه من جديد.
- إذا لم تكن أداة التحميل التي حدّدها المعرّف متوفرة،
يؤدي
initLoader()
إلى تشغيل طريقةLoaderManager.LoaderCallbacks
onCreateLoader()
هذا هو المكان الذي تنفذ فيه التعليمة البرمجية لإنشاء مثيل وعرض أداة تحميل جديدة. لمزيد من النقاشات، راجِع القسم حولonCreateLoader
.
في كلتا الحالتين، قيمة السمة LoaderManager.LoaderCallbacks
المحددة
يرتبط تنفيذ هذا الإجراء بالقائم بالتحميل، ويتم استدعاؤه عندما
تغييرات حالة برنامج التحميل. إذا كان المتصل في نقطة هذه المكالمة
برنامج التحميل المطلوب وبرنامج التحميل المطلوب وقد تم إنشاؤه
البيانات، فسيتصل النظام بـ onLoadFinished()
مباشرةً خلال initLoader()
. يجب أن تكون مستعدًا لذلك. لمزيد من المناقشة حول معاودة الاتصال هذه، راجع القسم حول
onLoadFinished
تُرجع الطريقة initLoader()
القيمة Loader
التي يتم إنشاؤها،
لكنك لا تحتاج إلى التقاط إشارة إليها. يدير LoaderManager
عمر التحميل تلقائيًا. LoaderManager
يبدأ ويتوقف التحميل عند الضرورة مع الحفاظ على حالة التحميل
والمحتوى المرتبط بها.
يعني ذلك أنّك نادرًا ما تتفاعل مع برامج التحميل
مباشرةً.
تستخدم طرق LoaderManager.LoaderCallbacks
الأكثر شيوعًا للتدخل في عملية التحميل.
العملية عند وقوع أحداث معينة. لمزيد من المناقشة لهذا الموضوع، يمكنك الاطّلاع على القسم استخدام استدعاءات LoaderManager.
إعادة تشغيل إحدى عمليات التحميل
عند استخدام initLoader()
، باعتباره
كما هو موضح في القسم السابق، فإنه يستخدم أداة تحميل حالية بالمعرّف المحدد، إن وجد.
إذا لم تكن موجودة، فهذا يؤدي إلى إنشاء واحد. لكن في بعض الأحيان تريد تجاهل بياناتك القديمة
والبدء من جديد.
لتجاهل البيانات القديمة، استخدِم "restartLoader()
". على سبيل المثال، ما يلي
تنفيذ عمليات إعادة تشغيل SearchView.OnQueryTextListener
برنامج التحميل عند تغيير استعلام المستخدم. يجب إعادة تشغيل برنامج التحميل لكي
يمكنه استخدام فلتر البحث المنقّح لإجراء طلب بحث جديد.
Kotlin
fun onQueryTextChanged(newText: String?): Boolean { // Called when the action bar search text has changed. Update // the search filter and restart the loader to do a new query // with this filter. curFilter = if (newText?.isNotEmpty() == true) newText else null supportLoaderManager.restartLoader(0, null, this) return true }
Java
public boolean onQueryTextChanged(String newText) { // Called when the action bar search text has changed. Update // the search filter, and restart the loader to do a new query // with this filter. curFilter = !TextUtils.isEmpty(newText) ? newText : null; getSupportLoaderManager().restartLoader(0, null, this); return true; }
استخدام استدعاءات LoaderManager
LoaderManager.LoaderCallbacks
هي واجهة لمعاودة الاتصال
تُتيح للعميل التفاعل مع LoaderManager
.
من المتوقّع أن تنفّذ عمليات التحميل، لا سيّما CursorLoader
،
الاحتفاظ ببياناتها بعد إيقافها. يسمح هذا للتطبيقات بالاحتفاظ
بالبيانات عبر طريقتَي onStop()
وonStart()
الخاصتَين بالنشاط أو الجزء، وذلك لكي
عند عودة المستخدمين إلى أحد التطبيقات، لن يضطروا إلى انتظار البيانات
إعادة التحميل.
يمكنك استخدام طرق LoaderManager.LoaderCallbacks
لمعرفة الوقت المناسب لإنشاء أداة تحميل جديدة وإعلام التطبيق بذلك.
الوقت اللازم للتوقف عن استخدام بيانات برنامج التحميل.
تتضمن LoaderManager.LoaderCallbacks
هذه
الطرق:
onCreateLoader()
: ينشئ مثيلاً ويعرض قيمةLoader
جديدة للمعرّف المحدّد.
-
onLoadFinished()
: يتم استدعاؤه عندما ينتهي تحميل برنامج تحميل تم إنشاؤه مسبقًا.
onLoaderReset()
: عند إعادة تعيين برنامج تحميل تم إنشاؤه مسبقًا، ومن ثم يصبح البيانات غير متوفرة.
يتم تناول هذه الطرق بمزيد من التفصيل في الأقسام التالية.
OnCreateLoader
عندما تحاول الوصول إلى أداة تحميل، من خلال initLoader()
مثلاً، تتحقق الأداة لمعرفة ما إذا
توجد أداة التحميل المحددة بواسطة المعرف. وفي حال عدم حدوث ذلك، سيتم تشغيل طريقة LoaderManager.LoaderCallbacks
onCreateLoader()
. هذا النمط
هي المكان الذي تقوم فيه بإنشاء تحميل جديد. تكون هذه الفئة عادةً CursorLoader
، ولكن يمكنك تنفيذ فئتك الفرعية Loader
.
في المثال التالي، تشير السمة onCreateLoader()
تنشئ طريقة استدعاء الدالة CursorLoader
باستخدام طريقة الدالة الإنشائية، والتي
مجموعة كاملة من المعلومات اللازمة لإجراء طلب بحث في ContentProvider
. وعلى وجه التحديد، يحتاج المتصفّح إلى ما يلي:
- uri: معرّف الموارد المنتظم (URI) للمحتوى المطلوب استرداده.
- projection: قائمة بالأعمدة المطلوب عرضها. تمرير الكرة
تعرض
null
جميع الأعمدة، وهي غير فعّالة. - الاختيار: فلتر يحدِّد الصفوف المطلوب عرضها
تنسيق كعبارة SQL WHERE (باستثناء WHERE نفسه). تمرير الكرة
تعرض
null
جميع الصفوف لمعرّف الموارد المنتظم (URI) المحدّد. - selectionArgs: إذا أدرجت ?s في التحديد، سيتم يتم استبدالها بالقيم من selectionArgs بالترتيب الذي تظهر فيه التحديد. يتم ربط القيم كسلاسل.
- sortOrder: كيفية ترتيب الصفوف، المنسقة كـ SQL
عبارة ORDER BY (باستثناء ORDER BY نفسها). جارٍ اجتياز الاختبار:
null
تستخدم نظام الفرز الافتراضي، الذي قد يكون غير مرتب.
Kotlin
// If non-null, this is the current filter the user has provided. private var curFilter: String? = null ... override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor> { // This is called when a new Loader needs to be created. This // sample only has one Loader, so we don't care about the ID. // First, pick the base URI to use depending on whether we are // currently filtering. val baseUri: Uri = if (curFilter != null) { Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, Uri.encode(curFilter)) } else { ContactsContract.Contacts.CONTENT_URI } // Now create and return a CursorLoader that will take care of // creating a Cursor for the data being displayed. val select: String = "((${Contacts.DISPLAY_NAME} NOTNULL) AND (" + "${Contacts.HAS_PHONE_NUMBER}=1) AND (" + "${Contacts.DISPLAY_NAME} != ''))" return (activity as? Context)?.let { context -> CursorLoader( context, baseUri, CONTACTS_SUMMARY_PROJECTION, select, null, "${Contacts.DISPLAY_NAME} COLLATE LOCALIZED ASC" ) } ?: throw Exception("Activity cannot be null") }
Java
// If non-null, this is the current filter the user has provided. String curFilter; ... public Loader<Cursor> onCreateLoader(int id, Bundle args) { // This is called when a new Loader needs to be created. This // sample only has one Loader, so we don't care about the ID. // First, pick the base URI to use depending on whether we are // currently filtering. Uri baseUri; if (curFilter != null) { baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode(curFilter)); } else { baseUri = Contacts.CONTENT_URI; } // Now create and return a CursorLoader that will take care of // creating a Cursor for the data being displayed. String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND (" + Contacts.HAS_PHONE_NUMBER + "=1) AND (" + Contacts.DISPLAY_NAME + " != '' ))"; return new CursorLoader(getActivity(), baseUri, CONTACTS_SUMMARY_PROJECTION, select, null, Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"); }
تم الانتهاء من التحميل
ويتم استدعاء هذه الطريقة عندما ينتهي تحميل برنامج تحميل تم إنشاؤه مسبقًا. نضمن لك طلب هذه الطريقة قبل إصدار البيانات الأخيرة التي يتم توفيرها لبرنامج التحميل هذا. في هذه المرحلة، قم بإزالة جميع استخدامات البيانات القديمة، حيث سيتم إصدارها. لكن لا تصدر البيانات نفسك — يمتلكه المسئول ويتولى ذلك.
يطلق برنامج التحميل البيانات بعد أن يعلم أن التطبيق لم يعد
استخدامه. على سبيل المثال، إذا كانت البيانات عبارة عن مؤشر من CursorLoader
،
لا تطلب close()
من خلاله بنفسك. إذا كان المؤشر قيد
وضعها في CursorAdapter
، فاستخدم طريقة swapCursor()
بحيث
لم يتم إغلاق Cursor
القديم، كما هو موضح في المثال التالي:
Kotlin
private lateinit var adapter: SimpleCursorAdapter ... override fun onLoadFinished(loader: Loader<Cursor>, data: Cursor?) { // Swap the new cursor in. (The framework will take care of closing the // old cursor once we return.) adapter.swapCursor(data) }
Java
// This is the Adapter being used to display the list's data. SimpleCursorAdapter adapter; ... public void onLoadFinished(Loader<Cursor> loader, Cursor data) { // Swap the new cursor in. (The framework will take care of closing the // old cursor once we return.) adapter.swapCursor(data); }
عند إعادة تعيين
ويتم استدعاء هذه الطريقة عند إعادة ضبط أداة تحميل تم إنشاؤها مسبقًا، ومن ثم مما يجعل بياناته غير متوفرة. تتيح لك معاودة الاتصال هذه معرفة متى يتم على وشك أن يتم إصداره حتى تتمكن من إزالة الإشارة إليه.
يتطلّب هذا التنفيذ
swapCursor()
بقيمة null
:
Kotlin
private lateinit var adapter: SimpleCursorAdapter ... override fun onLoaderReset(loader: Loader<Cursor>) { // This is called when the last Cursor provided to onLoadFinished() // above is about to be closed. We need to make sure we are no // longer using it. adapter.swapCursor(null) }
Java
// This is the Adapter being used to display the list's data. SimpleCursorAdapter adapter; ... public void onLoaderReset(Loader<Cursor> loader) { // This is called when the last Cursor provided to onLoadFinished() // above is about to be closed. We need to make sure we are no // longer using it. adapter.swapCursor(null); }
مثال
على سبيل المثال، في ما يلي التنفيذ الكامل للسمة Fragment
التي تعرض ListView
وتحتوي على
نتائج الاستعلام مقابل موفر محتوى جهات الاتصال. وهو يستخدم CursorLoader
لإدارة طلب البحث على مقدّم الخدمة.
ونظرًا لأن هذا المثال وارد من أحد التطبيقات للدخول إلى جهات اتصال أحد المستخدمين، فإن
يجب أن يتضمن البيان الإذن
READ_CONTACTS
Kotlin
private val CONTACTS_SUMMARY_PROJECTION: Array<String> = arrayOf( Contacts._ID, Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS, Contacts.CONTACT_PRESENCE, Contacts.PHOTO_ID, Contacts.LOOKUP_KEY ) class CursorLoaderListFragment : ListFragment(), SearchView.OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> { // This is the Adapter being used to display the list's data. private lateinit var mAdapter: SimpleCursorAdapter // If non-null, this is the current filter the user has provided. private var curFilter: String? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Prepare the loader. Either re-connect with an existing one, // or start a new one. loaderManager.initLoader(0, null, this) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // Give some text to display if there is no data. In a real // application, this would come from a resource. setEmptyText("No phone numbers") // We have a menu item to show in action bar. setHasOptionsMenu(true) // Create an empty adapter we will use to display the loaded data. mAdapter = SimpleCursorAdapter(activity, android.R.layout.simple_list_item_2, null, arrayOf(Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS), intArrayOf(android.R.id.text1, android.R.id.text2), 0 ) listAdapter = mAdapter } override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { // Place an action bar item for searching. menu.add("Search").apply { setIcon(android.R.drawable.ic_menu_search) setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM) actionView = SearchView(activity).apply { setOnQueryTextListener(this@CursorLoaderListFragment) } } } override fun onQueryTextChange(newText: String?): Boolean { // Called when the action bar search text has changed. Update // the search filter, and restart the loader to do a new query // with this filter. curFilter = if (newText?.isNotEmpty() == true) newText else null loaderManager.restartLoader(0, null, this) return true } override fun onQueryTextSubmit(query: String): Boolean { // Don't care about this. return true } override fun onListItemClick(l: ListView, v: View, position: Int, id: Long) { // Insert desired behavior here. Log.i("FragmentComplexList", "Item clicked: $id") } override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor> { // This is called when a new Loader needs to be created. This // sample only has one Loader, so we don't care about the ID. // First, pick the base URI to use depending on whether we are // currently filtering. val baseUri: Uri = if (curFilter != null) { Uri.withAppendedPath(Contacts.CONTENT_URI, Uri.encode(curFilter)) } else { Contacts.CONTENT_URI } // Now create and return a CursorLoader that will take care of // creating a Cursor for the data being displayed. val select: String = "((${Contacts.DISPLAY_NAME} NOTNULL) AND (" + "${Contacts.HAS_PHONE_NUMBER}=1) AND (" + "${Contacts.DISPLAY_NAME} != ''))" return (activity as? Context)?.let { context -> CursorLoader( context, baseUri, CONTACTS_SUMMARY_PROJECTION, select, null, "${Contacts.DISPLAY_NAME} COLLATE LOCALIZED ASC" ) } ?: throw Exception("Activity cannot be null") } override fun onLoadFinished(loader: Loader<Cursor>, data: Cursor) { // Swap the new cursor in. (The framework will take care of closing the // old cursor once we return.) mAdapter.swapCursor(data) } override fun onLoaderReset(loader: Loader<Cursor>) { // This is called when the last Cursor provided to onLoadFinished() // above is about to be closed. We need to make sure we are no // longer using it. mAdapter.swapCursor(null) } }
Java
public static class CursorLoaderListFragment extends ListFragment implements OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> { // This is the Adapter being used to display the list's data. SimpleCursorAdapter mAdapter; // If non-null, this is the current filter the user has provided. String curFilter; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Prepare the loader. Either re-connect with an existing one, // or start a new one. getLoaderManager().initLoader(0, null, this); } @Override public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); // Give some text to display if there is no data. In a real // application, this would come from a resource. setEmptyText("No phone numbers"); // We have a menu item to show in action bar. setHasOptionsMenu(true); // Create an empty adapter we will use to display the loaded data. mAdapter = new SimpleCursorAdapter(getActivity(), android.R.layout.simple_list_item_2, null, new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS }, new int[] { android.R.id.text1, android.R.id.text2 }, 0); setListAdapter(mAdapter); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { // Place an action bar item for searching. MenuItem item = menu.add("Search"); item.setIcon(android.R.drawable.ic_menu_search); item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); SearchView sv = new SearchView(getActivity()); sv.setOnQueryTextListener(this); item.setActionView(sv); } public boolean onQueryTextChange(String newText) { // Called when the action bar search text has changed. Update // the search filter, and restart the loader to do a new query // with this filter. curFilter = !TextUtils.isEmpty(newText) ? newText : null; getLoaderManager().restartLoader(0, null, this); return true; } @Override public boolean onQueryTextSubmit(String query) { // Don't care about this. return true; } @Override public void onListItemClick(ListView l, View v, int position, long id) { // Insert desired behavior here. Log.i("FragmentComplexList", "Item clicked: " + id); } // These are the Contacts rows that we will retrieve. static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] { Contacts._ID, Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS, Contacts.CONTACT_PRESENCE, Contacts.PHOTO_ID, Contacts.LOOKUP_KEY, }; public Loader<Cursor> onCreateLoader(int id, Bundle args) { // This is called when a new Loader needs to be created. This // sample only has one Loader, so we don't care about the ID. // First, pick the base URI to use depending on whether we are // currently filtering. Uri baseUri; if (curFilter != null) { baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode(curFilter)); } else { baseUri = Contacts.CONTENT_URI; } // Now create and return a CursorLoader that will take care of // creating a Cursor for the data being displayed. String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND (" + Contacts.HAS_PHONE_NUMBER + "=1) AND (" + Contacts.DISPLAY_NAME + " != '' ))"; return new CursorLoader(getActivity(), baseUri, CONTACTS_SUMMARY_PROJECTION, select, null, Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"); } public void onLoadFinished(Loader<Cursor> loader, Cursor data) { // Swap the new cursor in. (The framework will take care of closing the // old cursor once we return.) mAdapter.swapCursor(data); } public void onLoaderReset(Loader<Cursor> loader) { // This is called when the last Cursor provided to onLoadFinished() // above is about to be closed. We need to make sure we are no // longer using it. mAdapter.swapCursor(null); } }
مزيد من الأمثلة
توضّح الأمثلة التالية كيفية استخدام برامج التحميل:
- LoaderCursor: هو نسخة كاملة من المقتطف السابق.
- استرداد قائمة بجهات الاتصال:
جولة تفصيلية تستخدم
CursorLoader
لاسترداد البيانات من مزود جهات الاتصال. - LoaderThrottle: مثال على كيفية استخدام ميزة التقييد لتقليل عدد من طلبات البحث التي يُجريها موفر المحتوى عندما تتغير بياناته.