تم إيقاف أدوات التحميل نهائيًا بدءًا من نظام التشغيل Android 9 (المستوى 28 من واجهة برمجة التطبيقات). ننصح باستخدام مزيج من كائنات ViewModel
وLiveData
معًا للتعامل مع تحميل البيانات أثناء معالجة دورات حياة Activity
وFragment
.
تتيح لك هذه النماذج الاطّلاع على التغييرات التي تطرأ على الإعدادات، مثل برامج التحميل، ولكن باستخدام رمز نموذجي أقل. توفِّر LiveData
طريقة تراعي مراحل النشاط لتحميل البيانات والتي يمكنك إعادة استخدامها في نماذج طرق عرض متعدّدة. يمكنك أيضًا دمج LiveData
باستخدام
MediatorLiveData
.
يمكن استخدام أي طلبات بحث يمكن ملاحظتها، مثل تلك الواردة من قاعدة بيانات غرفة، لملاحظة التغييرات في البيانات.
يكون ViewModel
وLiveData
أيضًا متاحَين في الحالات التي لا يمكنك فيها
الوصول إلى LoaderManager
، مثلاً في
Service
. يوفر استخدام الاثنين معًا طريقة سهلة للوصول إلى البيانات التي يحتاجها تطبيقك دون الحاجة إلى التعامل مع دورة حياة واجهة المستخدم. لمزيد من المعلومات حول LiveData
، يمكنك الاطّلاع على
نظرة عامة على LiveData
. لمزيد من المعلومات حول
ViewModel
، يمكنك الاطّلاع على نظرة عامة على ViewModel
.
تتيح لك Loader API تحميل بيانات من موفّر محتوى أو مصدر بيانات آخر لعرضها في FragmentActivity
أو Fragment
.
بدون برامج التحميل، تتضمن بعض المشكلات التي قد تواجهها ما يلي:
- في حال جلب البيانات مباشرةً في النشاط أو الجزء، يعاني المستخدمون من عدم استجابة المستخدمين بسبب تنفيذ طلبات بحث يُحتمل أن تكون بطيئة من سلسلة محادثات واجهة المستخدم.
- في حال جلب البيانات من سلسلة محادثات أخرى، مثلاً من خلال
AsyncTask
، ستكون مسؤولاً عن إدارة كل من سلسلة المحادثات هذه وسلسلة محادثات واجهة المستخدم من خلال أنشطة مختلفة أو أحداث مراحل نشاط مجزأة، مثلonDestroy()
والتغييرات على الإعدادات.
تحل اللواحق هذه المشكلات وتتضمن مزايا أخرى:
- تعمل برامج التحميل على سلاسل محادثات منفصلة لمنع ظهور واجهة مستخدم بطيئة أو لا تستجيب.
- تبسّط أدوات التحميل إدارة سلسلة المحادثات من خلال توفير طرق لرد الاتصال عند وقوع الأحداث.
- تظل برامج التحميل وتحفظ النتائج في ذاكرة التخزين المؤقت في جميع تغييرات الإعدادات لمنع طلبات البحث المكررة.
- يمكن لبرامج التحميل استخدام أداة مراقبة لرصد التغييرات في مصدر
البيانات الأساسي. على سبيل المثال، تسجِّل
CursorLoader
تلقائيًاContentObserver
لتشغيل عملية إعادة تحميل عند تغيير البيانات.
ملخص واجهة برمجة تطبيقات Loader
هناك فئات وواجهات متعددة يمكن أن يتم تضمينها عند استخدام أدوات التحميل في أحد التطبيقات. ويتم تلخيصها في الجدول التالي:
الصف/الواجهة | الوصف |
---|---|
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
إلى عرض جميع الأعمدة، وهي طريقة غير فعّالة. - sselect: فلتر يحدد الصفوف المراد عرضها، ويكون منسَّقًا كفقرة SQL WHERE (باستثناء WHERE). يؤدي تمرير
null
إلى عرض جميع الصفوف لعنوان URI محدّد. - sselectArgs: إذا أدرجت ?s في التحديد، سيتم استبدالها بالقيم من sselectArgs بالترتيب الذي تظهر به في التحديد. يتم ربط القيم كسلاسل.
- 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"); }
onLoadEnded
يتم استدعاء هذه الطريقة عند انتهاء تحميل برنامج التحميل الذي تم إنشاؤه مسبقًا. ومن المضمون طلب هذه الطريقة قبل إصدار البيانات الأخيرة التي تم توفيرها لهذا التحميل. في هذه المرحلة، قم بإزالة كل استخدام البيانات القديمة، حيث سيتم إصدارها. ولكن لا تطلق البيانات بنفسك، فإن التحميل يمتلكها ويهتم بها.
يقوم برنامج التحميل بتحرير البيانات بمجرد معرفة أن التطبيق لم يعد يستخدمها. على سبيل المثال، إذا كانت البيانات هي مؤشر من 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); }
onLoaderReset
تُستدعى هذه الطريقة عند إعادة تعيين برنامج التحميل الذي تم إنشاؤه مسبقًا، ما يؤدي إلى عدم توفر بياناته. تتيح لك معاودة الاتصال هذه معرفة الوقت الذي أوشك فيه إصدار البيانات حتى تتمكن من إزالة الإشارة إليها.
يستدعي هذا الإجراء
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: مثال على كيفية استخدام التقييد لتقليل عدد طلبات البحث التي يجريها موفّر المحتوى عندما تتغير بياناته.