लोडर

Android 9 (एपीआई लेवल 28) के बाद से, लोडर बंद कर दिए गए हैं. इसके लिए सुझाया गया विकल्प Activity और Fragment लाइफ़साइकल को हैंडल करते समय, लोड होने वाले डेटा से निपटने के लिए ViewModel ऑब्जेक्ट का कॉम्बिनेशन और LiveData. व्यू मॉडल, लोडर की तरह कॉन्फ़िगरेशन में होने वाले बदलावों के बाद भी बचे रहते हैं, लेकिन कम बॉयलरप्लेट कोड. LiveData, डेटा लोड होने की लाइफ़साइकल के बारे में जानकारी देने वाला तरीका उपलब्ध कराता है. इसे फिर से इस्तेमाल किया जा सकता है एक से ज़्यादा व्यू मॉडल का इस्तेमाल कर सकते हैं. LiveData को जोड़ने के लिए, यह तरीका भी अपनाया जा सकता है: MediatorLiveData. कोई भी मॉनिटर की जा सकने वाली क्वेरी, जैसे कि रूम डेटाबेस, इसका इस्तेमाल बदलावों के बारे में जानने के लिए किया जा सकता है ही डेटा में शामिल हो सकते हैं.

ViewModel और LiveData उन स्थितियों में भी उपलब्ध होते हैं जहां आपके पास इसका ऐक्सेस नहीं है को LoaderManager के लिए, जैसे कि Service. दोनों को Google में टैन्डम, आपके ऐप्लिकेशन के लिए ज़रूरी डेटा को ऐक्सेस करने का आसान तरीका मुहैया कराता है. इसके लिए, यूज़र इंटरफ़ेस (यूआई) की ज़रूरत नहीं होती लाइफ़साइकल. LiveData के बारे में ज़्यादा जानने के लिए, यहां जाएं: LiveData खास जानकारी. इस बारे में ज़्यादा जानने के लिए ViewModel, ViewModel की खास जानकारी देखें.

Loader API की मदद से, किसी कॉन्टेंट देने वाला या FragmentActivity में दिखाने के लिए कोई दूसरा डेटा सोर्स या Fragment.

लोडर न होने पर, आपको नीचे दी गई कुछ समस्याओं का सामना करना पड़ सकता है:

  • अगर सीधे गतिविधि या फ़्रैगमेंट में डेटा फ़ेच किया जाता है, तो आपके उपयोगकर्ता संभावित रूप से धीमे काम करने की वजह से, रिस्पॉन्स में समय की कमी की समस्या से जूझ रहे हैं यूज़र इंटरफ़ेस (यूआई) थ्रेड से क्वेरी.
  • अगर आपको किसी दूसरे थ्रेड से डेटा फ़ेच करना है, तो शायद AsyncTask से, तो दोनों थ्रेड को मैनेज करने की ज़िम्मेदारी आपकी होगी यूज़र इंटरफ़ेस (यूआई) थ्रेड को कई तरह की गतिविधि या फ़्रैगमेंट लाइफ़साइकल इवेंट के ज़रिए दिखाया जाता है. जैसे, onDestroy() और कॉन्फ़िगरेशन में बदलाव किए गए हैं.

लोडर इन समस्याओं को हल करते हैं और इनके दूसरे फ़ायदे भी हैं:

  • धीमे या काम नहीं करने वाले यूज़र इंटरफ़ेस (यूआई) को रोकने के लिए, लोडर अलग-अलग थ्रेड पर चलते हैं.
  • इवेंट के दौरान, लोडर कॉलबैक मैथड देकर थ्रेड मैनेजमेंट को आसान बनाते हैं होता है.
  • इस विकल्प को रोकने के लिए, लोडर सभी कॉन्फ़िगरेशन में बदलावों को बनाए रखते हैं और नतीजों को कैश मेमोरी में सेव करते हैं डुप्लीकेट क्वेरी.
  • लोडर, ऑब्ज़र्वर को लागू करके, मौजूदा डेटा के बदलावों की निगरानी कर सकते हैं डेटा सोर्स. उदाहरण के लिए, CursorLoader अपने-आप फिर से लोड करने के लिए ContentObserver रजिस्टर करता है जब डेटा बदलता है.

Loader API के बारे में खास जानकारी

ऐसी कई क्लास और इंटरफ़ेस हैं जो 'टूल' का इस्तेमाल करते समय लोडर का इस्तेमाल किया जा सकता है. इनकी खास जानकारी यहां दी गई टेबल में दी गई है:

क्लास/इंटरफ़ेस ब्यौरा
LoaderManager FragmentActivity या से जुड़ी ऐब्स्ट्रैक्ट क्लास एक या उससे ज़्यादा मैनेज करने के लिए Fragment Loader इंस्टेंस. यहां सिर्फ़ एक हर गतिविधि या फ़्रैगमेंट के लिए LoaderManager, लेकिन LoaderManager, एक से ज़्यादा लोडर मैनेज कर सकता है.

LoaderManager पाने के लिए, getSupportLoaderManager() पर कॉल करें ऐक्टिविटी या फ़्रैगमेंट से बाहर रखा जाता है.

लोडर से डेटा लोड करना शुरू करने के लिए, इनमें से किसी एक को कॉल करें initLoader() या restartLoader(). सिस्टम अपने-आप पता लगाता है कि एक ही पूर्णांक आईडी वाला लोडर पहले से है या नहीं मौजूद है और या तो नया लोडर बनाता है या मौजूदा लोडर का फिर से इस्तेमाल करता है.

LoaderManager.LoaderCallbacks इस इंटरफ़ेस में कॉलबैक मेथड होते हैं. इन्हें तब कॉल किया जाता है, जब लोडर इवेंट होते हैं. इंटरफ़ेस में तीन कॉलबैक तरीके बताए गए हैं:
  • onCreateLoader(int, Bundle): तब कॉल किया जाता है, जब सिस्टम को कोई नया लोडर बनाने की ज़रूरत होती है. अपने कोड में, कोई Loader ऑब्जेक्ट बनाएं और उसे वापस भेजें शामिल हैं.
  • onLoadFinished(Loader<D>, D): जब कोई लोडर डेटा लोड करना पूर्ण कर लेता है, तब कॉल किया जाता है. आम तौर पर उपयोगकर्ता को आपके कोड में डेटा दिखाता है.
  • onLoaderReset(Loader<D>): जब पहले से बनाए गए लोडर को रीसेट किया जा रहा हो, तब कॉल किया जाता है destroyLoader(int) या गतिविधि कब की जाएगी या फ़्रैगमेंट खत्म हो जाता है, जिससे उसका डेटा उपलब्ध नहीं होता. अपने कोड में, लोडर के डेटा के सभी संदर्भ निकाल सकते हैं.
आपकी ऐक्टिविटी या फ़्रैगमेंट आम तौर पर इस इंटरफ़ेस को लागू करता है और आपके कॉल करने पर रजिस्टर हो जाता है initLoader() या restartLoader().
Loader लोडर डेटा लोड करने का काम करते हैं. यह क्लास ऐब्सट्रैक्ट है और इसमें अपनी सेवाएं देती है लोड करने वाले सभी लोगों की बेस क्लास के तौर पर. सीधे तौर पर सब-क्लास बनाई जा सकती है Loader या पहले से मौजूद इनमें से किसी एक का इस्तेमाल करें सब-क्लास का इस्तेमाल करके, आसानी से लागू किया जा सकता है:
  • AsyncTaskLoader: एक ऐब्स्ट्रैक्ट लोडर, जो इस बाहरी सोर्स पर लोड करने के लिए एक AsyncTask उपलब्ध कराता है थ्रेड.
  • CursorLoader: इसकी एक ठोस सब-क्लास एसिंक्रोनस रूप से लोड होने वाले डेटा के लिए AsyncTaskLoader ContentProvider से मिला है. यह ContentResolver और यह Cursor.

नीचे दिए गए सेक्शन में, क्लास और इंटरफ़ेस पर मौजूद हैं.

ऐप्लिकेशन में लोडर का इस्तेमाल करना

इस सेक्शन में किसी Android ऐप्लिकेशन में लोडर इस्तेमाल करने का तरीका बताया गया है. अगर आप लोडर का इस्तेमाल करने वाले ऐप्लिकेशन में आम तौर पर ये चीज़ें शामिल होती हैं:

  • FragmentActivity या Fragment.
  • LoaderManager का एक इंस्टेंस.
  • ContentProvider के साथ काम करने वाला डेटा लोड करने के लिए CursorLoader. इसके अलावा, अपने हिसाब से सब-क्लास भी लागू की जा सकती है Loader या AsyncTaskLoader का किसी अन्य सोर्स से डेटा लोड करें.
  • LoaderManager.LoaderCallbacks के लिए लागू करने की प्रक्रिया. यहां पर आप नए लोडर बनाते हैं और मौजूदा लोडर.
  • लोड करने वाले के डेटा को दिखाने का एक तरीका, जैसे कि SimpleCursorAdapter.
  • डेटा सोर्स, जैसे कि ContentProvider, जब CursorLoader.

लोडर चालू करें

LoaderManager, FragmentActivity में एक या उससे ज़्यादा Loader इंस्टेंस मैनेज करता है या Fragment. हर गतिविधि या फ़्रैगमेंट के लिए सिर्फ़ एक LoaderManager होता है.

आम तौर पर गतिविधि के onCreate() तरीके या फ़्रैगमेंटLoader 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(): तब कॉल किया जाता है जब पहले से बनाए गए लोडर को रीसेट किया जा रहा होता है, जिससे यह डेटा अनुपलब्ध.

नीचे दिए गए सेक्शन में, इन तरीकों के बारे में ज़्यादा जानकारी दी गई है.

ऑनCreateLoader

जब initLoader() जैसी किसी लोडर को ऐक्सेस करने की कोशिश की जाती है, तो यह जांच की जाती है कि क्या आईडी से तय किया गया लोडर मौजूद है. अगर ऐसा नहीं होता है, तो यह LoaderManager.LoaderCallbacks तरीका onCreateLoader() ट्रिगर करता है. यह नया लोडर बनाया जाता है. आम तौर पर, यह एक CursorLoader है, लेकिन आपके पास अपनी Loader सब-क्लास लागू करने का विकल्प होता है.

नीचे दिए गए उदाहरण में, onCreateLoader() कॉलबैक मेथड अपने कंस्ट्रक्टर का इस्तेमाल करके, एक CursorLoader बनाता है. ContentProvider पर कोई क्वेरी करने के लिए, जानकारी के पूरे सेट की ज़रूरत होती है. खास तौर पर, इसे इनकी ज़रूरत होती है:

  • uri: कॉन्टेंट को वापस पाने के लिए यूआरआई.
  • प्रोजेक्शन: लौटाए जाने वाले कॉलम की सूची. पासिंग null सभी कॉलम दिखाता है, जो कि अच्छी तरह काम नहीं करते.
  • चुनना: ऐसा फ़िल्टर जो बताता है कि कौनसी लाइन देखनी है, SQL WHERE क्लॉज़ के तौर पर फ़ॉर्मैट किया गया हो (इसमें WHERE को छोड़कर). पासिंग null दिए गए यूआरआई के लिए सभी पंक्तियां दिखाता है.
  • selectionArgs: चुनाव में ?s को शामिल करने पर, उनकी जगह selectionArgs की वैल्यू उसी क्रम में हैं, जिस क्रम में वे चुनें. वैल्यू, स्ट्रिंग के तौर पर बाउंड होती हैं.
  • sortOrder: एसक्यूएल के फ़ॉर्मैट में पंक्तियों को कैसे ऑर्डर करें ORDER BY क्लॉज़ (ऑर्डर 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");
}

onLoadFinish किया गया

यह तरीका तब कॉल किया जाता है, जब पहले से बनाया गया लोडर अपना लोड पूरा कर लेता है. इस बात की गारंटी है कि पिछले डेटा की रिलीज़ से पहले इस तरीके को कॉल किया जाएगा जो इस लोडर के लिए दी गई है. इस स्थिति में, पुराना डेटा हटा दिया, क्योंकि वे रिलीज़ होने ही वाले हैं. हालाँकि, अपने संस्थान के डेटा को लोडर का मालिक होता है और वह इसका ध्यान रखता है.

ऐप्लिकेशन बंद होने के बाद, लोडर डेटा को रिलीज़ कर देता है उसका इस्तेमाल करना. उदाहरण के लिए, अगर डेटा, 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: इसमें, संख्या कम करने के लिए थ्रॉटलिंग इस्तेमाल करने के तरीके का उदाहरण दिया गया है उन क्वेरी का जवाब देता है जो कॉन्टेंट उपलब्ध कराने वाला संगठन डेटा में बदलाव होने पर करता है.