الأربعاء، 18 أكتوبر 2017

رافعات Loader


رافعات Loader


في هذه الوثيقة
لويدر أبي الملخص
استخدام لوادر في التطبيق
بدء محمل
إعادة تشغيل محمل
استخدام الاستدعاءات لوادرماناجر
مثال
مزيد من الأمثلة
الطبقات الرئيسية
LoaderManager
Loader
عينات ذات صلة
LoaderCursor
LoaderThrottle


مقدمة في الروبوت 3.0 (أبي مستوى 11)، لوادر أبي يتيح لك تحميل البيانات من مزود المحتوى أو غيرها من مصدر البيانات للعرض في Activity أو Fragment . إذا كنت لا تفهم لماذا كنت في حاجة إلى أبي لويدر لأداء هذه العملية تبدو تافهة، ثم أولا النظر في بعض المشاكل التي قد تواجهها دون لوادر:

إذا جلبت البيانات مباشرة في النشاط أو الشظية، فسيعاني المستخدمون من عدم الاستجابة بسبب أداء طلبات البحث التي قد تكون بطيئة من مؤشر ترابط واجهة المستخدم.
إذا قمت AsyncTask البيانات من سلسلة ترابط أخرى، ربما باستخدام AsyncTask ، فأنت مسؤول عن إدارة كل من سلسلة الترابط AsyncTask ترابط واجهة المستخدم من خلال نشاط مختلف أو أحداث دورة حياة الشظايا، مثل onDestroy() وتغييرات التهيئة.
لوادر حل هذه المشاكل ويشمل فوائد أخرى. فمثلا:

تشغيل اللوادر على المواضيع منفصلة لمنع واجهة المستخدم غريب الأطوار أو لا تستجيب.
لوادر تبسيط إدارة الموضوع من خلال توفير أساليب الاستدعاء عندما تحدث الأحداث.
تستمر اللوادر ونتائج التخزين المؤقت عبر تغييرات التكوين لمنع الاستعلامات المكررة.
يمكن لوادر التحميل تنفيذ مراقب لمراقبة التغيرات في مصدر البيانات الأساسي. على سبيل المثال، يقوم ContentObserver تلقائيا بتسجيل ContentObserver لتشغيل إعادة تحميل عند تغيير البيانات.
لويدر أبي الملخص
هناك فئات متعددة واجهات التي قد تكون مشتركة عند استخدام لوادر في التطبيق. وهي ملخصة في هذا الجدول:

الطبقة / واجهة وصف
LoaderManager فئة مجردة مرتبطة Fragment أو Fragment لإدارة مثيل Loader أو أكثر. هناك LoaderManager واحد فقط لكل نشاط أو جزء، ولكن LoaderManager يمكن إدارة لوادر متعددة.
للحصول على لوادرماناجر، اتصل getLoaderManager() من النشاط أو جزء.

لبدء تحميل البيانات من محمل، استدعاء إما initLoader() أو restartLoader() . يحدد النظام تلقائيا ما إذا كان محمل يحتوي على نفس الرقم الصحيح موجود بالفعل، وسوف إما إنشاء محمل جديد أو إعادة استخدام محمل موجود.
LoaderManager.LoaderCallbacks تحتوي هذه الواجهة على أساليب الاستدعاء التي تسمى عند حدوث أحداث لويدر. تحدد الواجهة ثلاث طرق للاستدعاء:
onCreateLoader(int, Bundle) - تسمى عندما يحتاج النظام إلى محمل جديد ليتم إنشاؤه. يجب أن تقوم التعليمات البرمجية بإنشاء كائن Loader وإعادته إلى النظام.
onLoadFinished(Loader<D>, D) - يسمى عند انتهاء تحميل onLoadFinished(Loader<D>, D) البيانات. عادة، يجب أن تعرض الشفرة البيانات للمستخدم.
onLoaderReset(Loader<D>) - عندما يتم إعادة تعيين محمل تم إنشاؤه مسبقا (عند استدعاء destroyLoader(int) أو عندما يتم تدمير النشاط أو جزء، وبالتالي جعل البيانات غير destroyLoader(int) أن إزالة التعليمات البرمجية أي مراجع أن بيانات المحمل.
يتم تنفيذ هذه الواجهة عادة بواسطة نشاطك أو جزء و يتم تسجيلها عند استدعاء initLoader() أو restartLoader() .
Loader لوادر تنفيذ تحميل البيانات. هذه الفئة هي مجردة وتستخدم بمثابة الطبقة الأساسية لجميع لوادر. يمكنك مباشرة فئة فرعية Loader أو استخدام واحدة من الفئات الفرعية المضمنة التالية لتبسيط التنفيذ:
AsyncTaskLoader - محمل مجرد يوفر AsyncTask لتنفيذ عمليات التحميل على مؤشر ترابط منفصل.
CursorLoader - فئة فرعية ملموسة من AsyncTaskLoader لتحميل البيانات بشكل غير متزامن من ContentProvider . فإنه يستعلم ContentResolver وإرجاع Cursor .
توضح الأقسام التالية كيفية استخدام هذه الفئات والواجهات في أحد التطبيقات.

استخدام لوادر في التطبيق
يصف هذا القسم كيفية استخدام لوادر في تطبيق الروبوت. يتضمن التطبيق الذي يستخدم اللوادر عادة ما يلي:

Activity أو Fragment .
مثيل LoaderManager .
A CursorLoader لتحميل البيانات التي تدعمها ContentProvider . بدلا من ذلك، يمكنك تنفيذ الفئة الفرعية الخاصة بك من Loader أو AsyncTaskLoader لتحميل البيانات من بعض المصادر الأخرى.
تنفيذ LoaderManager.LoaderCallbacks . هذا هو المكان الذي تقوم بإنشاء لوادر جديدة وإدارة المراجع الخاصة بك إلى لوادر الحالية.
طريقة لعرض بيانات المحمل، مثل SimpleCursorAdapter .
مصدر بيانات، مثل ContentProvider ، عند استخدام CursorLoader .
بدء محمل
يقوم LoaderManager بإدارة LoaderManager أو أكثر ضمن Activity أو Fragment . هناك LoaderManager واحد فقط لكل نشاط أو جزء.

تقوم عادة onCreate() Loader ضمن أسلوب onCreate() ، أو ضمن أسلوب onCreate() في الجزء. يمكنك القيام بذلك على النحو التالي:
// Prepare the loader.  Either re-connect with an existing one,
// or start a new one.
getLoaderManager().initLoader(0, null, this);

الأسلوب initLoader() يأخذ المعلمات التالية:

معرف فريد يحدد المحمل. في هذا المثال، الرقم التعريفي هو 0.
وسيطات اختيارية لتوريد المحمل عند الإنشاء ( null في هذا المثال).
تنفيذ LoaderManager.LoaderCallbacks ، الذي يدعو LoaderManager للإبلاغ عن أحداث اللوادر. في هذا المثال، الطبقة المحلية تنفذ واجهة LoaderManager.LoaderCallbacks ، لذلك يمر إشارة إلى نفسها، this .
تضمن المكالمة initLoader() أن المحمل initLoader() ونشط. ولها نتيجتان محتملتان:

إذا كان المحمل المحدد بواسطة المعرف موجود بالفعل، يتم إعادة استخدام آخر محمل تم إنشاؤه.
إذا كان المحمل المحدد بواسطة معرف غير موجود، initLoader() بتشغيل أسلوب onCreateLoader() . هذا هو المكان الذي تقوم بتنفيذ التعليمات البرمجية لإنشاء مثبت جديد وإرجاعه. لمزيد من المناقشة، راجع القسم على كريتلوادر .
في كلتا الحالتين، يتم LoaderManager.LoaderCallbacks تنفيذ LoaderManager.LoaderCallbacks معين مع محمل، وسيتم استدعاؤها عندما تتغير حالة المحمل. إذا كان في وقت هذه المكالمة المتصل في حالته بدأت، والمحمل المطلوب موجود بالفعل، وقد ولدت بياناتها، ثم يدعو النظام onLoadFinished() الفور (أثناء initLoader() )، لذلك يجب أن تكون على استعداد لهذا إلى يحدث. انظر أونلودفينيشد لمزيد من المناقشة حول هذا الاستدعاء

لاحظ أن الأسلوب initLoader() بإرجاع Loader الذي تم إنشاؤه، ولكن لا تحتاج إلى التقاط مرجع إليه. يدير LoaderManager حياة المحمل تلقائيا. LoaderManager يبدأ ويوقف التحميل عند الضرورة، ويحافظ على حالة من المحمل والمحتوى المرتبط بها. كما يعني ذلك، نادرا ما تتفاعل مع لوادر مباشرة (على الرغم من مثال على استخدام طرق محمل لضبط سلوك المحمل، راجع عينة لوادرثروتل ). تستخدم الأكثر شيوعا طرق LoaderManager.LoaderCallbacks للتدخل في عملية التحميل عند حدوث أحداث معينة. لمزيد من المناقشة حول هذا الموضوع، راجع استخدام استدعاءات لوادرماناجر .

إعادة تشغيل محمل
عند استخدام initLoader() ، كما هو موضح أعلاه، يستخدم محمل موجود مع معرف المحدد إذا كان هناك واحد. إذا لم يكن هناك، فإنه يخلق واحد. ولكن في بعض الأحيان كنت تريد تجاهل البيانات القديمة الخاصة بك والبدء من جديد.

لتجاهل البيانات القديمة، يمكنك استخدام restartLoader() . على سبيل المثال، يؤدي تنفيذ SearchView.OnQueryTextListener إعادة تشغيل المحمل عندما يتغير طلب بحث المستخدم. يجب إعادة تشغيل المحمل بحيث يمكنه استخدام فلتر البحث المنقح لإجراء استعلام جديد:

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.
    mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
    getLoaderManager().restartLoader(0, null, this);
    return true;
}


استخدام الاستدعاءات لوادرماناجر
LoaderManager.LoaderCallbacks هو واجهة رد الاتصال الذي يتيح للعميل التفاعل مع LoaderManager .

ومن المتوقع أن تحتفظ CursorLoader ، خاصة CursorLoader ، CursorLoader بعد إيقافها. يسمح هذا للتطبيقات بالاحتفاظ onStop() عبر النشاط أو onStop() و onStart() ، بحيث عندما يعود المستخدمون إلى أحد التطبيقات، لا يتعين عليهم الانتظار حتى يتم إعادة تحميل البيانات. يمكنك استخدام أساليب LoaderManager.LoaderCallbacks عند معرفة متى إنشاء محمل جديد، وإخبار التطبيق عندما حان الوقت للتوقف عن استخدام بيانات المحمل.

يتضمن LoaderManager.LoaderCallbacks هذه الطرق:

onCreateLoader() - onCreateLoader() وإرجاع Loader جديد للمعرف المعطى.
onLoadFinished() - دعا عند انتهاء محمل تم إنشاؤه مسبقا حملها.
onLoaderReset() - يسمى عندما يتم إعادة تعيين محمل تم إنشاؤه مسبقا، مما يجعل بياناتها غير متوفرة.
يتم وصف هذه الأساليب بمزيد من التفصيل في الأقسام التالية.

onCreateLoader
عند محاولة الوصول إلى محمل (على سبيل المثال، من خلال initLoader() )، فإنه يتحقق لمعرفة ما إذا كان محمل المحدد بواسطة معرف موجود. إذا لم يحدث ذلك، فإنه يؤدي إلى طريقة onCreateLoader() . هذا هو المكان الذي تقوم بإنشاء محمل جديد. وعادة ما يكون هذا CursorLoader ، ولكن يمكنك تنفيذ الفئة الفرعية Loader الخاصة بك.

في هذا المثال، يقوم أسلوب الاستدعاء onCreateLoader() بإنشاء CursorLoader . يجب إنشاء CursorLoader باستخدام طريقة CursorLoader ، والذي يتطلب مجموعة كاملة من المعلومات المطلوبة لإجراء استعلام إلى ContentProvider . وعلى وجه التحديد، فإنه يحتاج إلى:

أوري - عنوان أوري للمحتوى الذي سيتم استرداده.
الإسقاط - قائمة الأعمدة للعودة. سيؤدي تمرير null إلى إرجاع جميع الأعمدة، وهو أمر غير فعال.
سيلكتيون - مرشح يعلن الصفوف المراد إرجاعها، وتهيئتها كعبارة سكل وير (باستثناء وير نفسها). سيؤدي تمرير null إلى إرجاع جميع الصفوف لمعرف الموارد المنتظم (أوري) المحدد.
سيلكتيونس أرغس - يمكنك تضمين؟ s في التحديد، والتي سيتم استبدالها بالقيم من سيلاركاتيونس ، بالترتيب الذي تظهر به في التحديد. سيتم ربط القيم كسلاسل.
سورتوردر - كيفية ترتيب الصفوف، المنسقة كعبارة سكل أوردر بي (باستثناء أوردر بي نفسه). سوف يمر null استخدام الترتيب الفرز الافتراضي، والتي قد تكون غير مرتبة.
فمثلا:


 // If non-null, this is the current filter the user has provided.
String mCurFilter;
...
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 (mCurFilter != null) {
        baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
                  Uri.encode(mCurFilter));
    } 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");
}


onLoadFinished
يتم استدعاء هذا الأسلوب عند الانتهاء من محمل تم إنشاؤه مسبقا تحميله. هذه الطريقة مضمونة ليتم استدعاؤها قبل إصدار آخر البيانات التي تم توفيرها لهذا المحمل. عند هذه النقطة يجب إزالة جميع استخدام البيانات القديمة (لأنه سيتم الافراج قريبا)، ولكن لا ينبغي أن تفعل الإفراج الخاص بك من البيانات منذ لودر يملكها وسوف تأخذ الرعاية من ذلك.

سوف محمل الافراج عن البيانات بمجرد أن يعرف التطبيق لم يعد استخدامه. على سبيل المثال، إذا كانت البيانات مؤشر من CursorLoader ، يجب عدم الاتصال close() على ذلك بنفسك. إذا تم وضع المؤشر في swapCursor() ، يجب استخدام الأسلوب swapCursor() بحيث لا يتم إغلاق Cursor القديم. فمثلا:

// This is the Adapter being used to display the list's data.
SimpleCursorAdapter mAdapter;
...

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);
}

onLoaderReset
يتم استدعاء هذا الأسلوب عند إعادة تحميل محمل تم إنشاؤه مسبقا، مما يجعل البيانات غير متوفرة. يتيح لك رد الاتصال هذا معرفة متى يتم إطلاق البيانات حتى تتمكن من إزالة المرجع الخاص بك.

ويدعو هذا التنفيذ swapCursor() بقيمة null :


// This is the Adapter being used to display the list's data.
SimpleCursorAdapter mAdapter;
...

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);
}

مثال
على سبيل المثال، هنا هو التنفيذ الكامل Fragment يعرض قائمة ListView تحتوي على نتائج استعلام ضد موفر محتوى جهات الاتصال. يستخدم CursorLoader لإدارة الاستعلام على موفر.

للحصول على تطبيق للوصول إلى جهات اتصال المستخدم، كما هو موضح في هذا المثال، يجب أن يتضمن البيان الخاص به إذن READ_CONTACTS .


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 mCurFilter;

    @Override public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(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);

        // Prepare the loader.  Either re-connect with an existing one,
        // or start a new one.
        getLoaderManager().initLoader(0, null, this);
    }

    @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.
        mCurFilter = !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 (mCurFilter != null) {
            baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
                    Uri.encode(mCurFilter));
        } 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);
    }
}

مزيد من الأمثلة
توضح الأمثلة التالية كيفية استخدام اللوادر:

لويدركورسور - نسخة كاملة من المقتطف المبين أعلاه.
استرجاع قائمة جهات الاتصال - تجول يستخدم CursorLoader لاسترداد البيانات من موفر جهات الاتصال.
لويدرثروتل - مثال على كيفية استخدام الاختناق لتقليل عدد الاستعلامات التي يقوم بها موفر المحتوى عندما تتغير بياناته.
AsyncTaskLoader - مثال يستخدم AsyncTaskLoader لتحميل التطبيقات المثبتة حاليا من مدير الحزمة.

ليست هناك تعليقات:

إرسال تعليق

للوضع الليلي في التطبيق DayNight

في هذا البرنامج التعليمي ، سنناقش ونستخدم موضوع Android DayNight في تطبيقنا. إذا كان لديك تطبيق يحتوي على مواد للقراءة ، فإن استخدام الوض...