انشاء الـ ViewModel بـ Paging

Mohammad Laifمنذ سنة

بسم الله الرحمن الرحيم
السلام عليكم ورحمة الله وبركاته

في هذا الدرس سنتعلم كيفية انشاء كلاس ViewModel وبداخلها LiveData و تستخدم الـ Paging حتى نستطيع استخدام قاعدة البيانات Room من الـ Activity.

 

ماذا سننشئ؟

  • كلاس ViewModel لـ CardActivity.
  • كلاس Factory حتى نمكن حقن الـ ViewModel بالـ Paramters لاحقاً (بدون استخدام كتبة Dagger).

 

انشاء كلاس الـ ViewModel

ننشئ كلاس جديدة ولنسميها CardListViewModel ونجعلها تعمل Extends للكلاس AndroidViewModel (في حالة عمل Extends للـ ViewModel فانك لاستطيع انشاء Paramters في الـ Constructor) وسوف نقوم باستخدام هذه الكلاس لاحقاً في الـ Activity الذي تحتوي على RecyclerView ويكون الـ Adapter لها يستخدم تقنية الـ Paging وتعرض للمستخدم عناصر Cards). نقوم بانشاء حقلين بها الاول للـ Repository الخاص بعناصر الـ Card, والحقل الثاني عبارة عن LiveData تغلف List من نوع Paged لعناصر الـ Card من خلال id معين يمثله الحقل الثالث:

public class CardListViewModel extends AndroidViewModel {
    private CardRepository mRepository;
    private LiveData<PagedList<CardEntity>> mCardsByParentId;
    private final int mCardByParentId;
}

 

نقوم بانشاء Constructor يأخد Application (تستطيع جعله يأخد AppDatabase اذا احببت) من خلاله نقوم بعمل init لكل من حقولنا السابقه:

    public CardListViewModel(@NonNull Application application, final int cardParentId) {
        super(application);
        mCardByParentId = cardParentId;
        mRepository = CardRepository.getInstance(application);
        mCardsByParentId = mRepository.getAllCardsById(mCardByParentId);
    }

تعقيب:

  • لاحظ الـ Paramter الثاني cardParentId هو الذي سنقوم بعملية حقنه في هذه الـ ViewModel لاحقاً.

 

نقوم بكتابة دوال التعامل مع البيانات ومعالجتهم كـ insert و update و delete و query. ملاحظة مهمة هنا الـ ViewModel ستقوم بعمل Delegate الى الـ Repository والذي هو بدوره يقوم ايضاً بعمل Delegate الى الـ Dao ومن ثم الـ Dao تاتي لنا بالبيانات من قاعدة البيانات الـ Room:

    public LiveData<PagedList<CardEntity>> getCardsByParentId() {
        return mCardsByParentId;
    }

    public void insert(CardEntity cardEntity) {
        mRepository.insert(cardEntity);
    }

    public void update(CardEntity cardEntity) {
        mRepository.update(cardEntity);
    }

    public void delete(CardEntity cardEntity) {
        mRepository.delete(cardEntity);
    }

    public void deleteAll() {
        mRepository.deleteAll();
    }

تعقيب:

  • لاحظ الدالة getCardsByParentId لاتأخد id معين, وطريقة اعطائها id من خلال حقن هذه الـ ViewModel, وتعتبر طريقة الحقن هي الطريقة لتمرير Paramters الى الـ ViewModel.

 

كلاس Factory

واخيراً يجب علينا انشاء كلاس Factory حتى نستطيع من خلاله ادخال (حقن) Paramters للـ ViewModel التي سوف نعملها في الدروس لاحقاً:

    public static class Factory extends ViewModelProvider.NewInstanceFactory {

        @NonNull
        private final Application mApplication;
        private final int mCardParentId;

        public Factory(@NonNull Application application, int cardParentId) {
            mApplication = application;
            mCardParentId = cardParentId;
        }

        @NonNull
        @Override
        public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
            return (T) new CardListViewModel(mApplication, mCardParentId);
        }
    }

تعقيب:

  • قمنا بعمل extends للكلاس NewInstanceFactory الموجودة بداخل كلاس الـ ViewModelProvider (وهي المسؤول عن انشاء عناصر الـ ViewModel). لتصبح كلاسنا هذه هي المسؤوله عن انشاء ViewModel عندما نحتاجها في الـ Activity.
  • كما نلاحظ لدينا حقلين الاول عباره عن Application اما الثاني فهو العنصر المراد تمريره الى الـ ViewModel وفي حالتنا هو رقم الـ id معين mCardParentId.
  • ونعمل Constructor لهذه الحقول ثم نضع دالة create حتى تقوم بعمل instantiate للـ ViewModel.

لاتقم بتمرير Context او Views او Callbacks مطلقاً والا ستسبب بمشاكل وقلة الاداء في تطبيقك (احتمالية الـ Memory Leak واردة جداً) تستطيع فقط تمرير الـ Application واستخدامه كـ Context اذا دعت الحاجة.

هل توجد طرق اخرى؟

  • نعم تستطيع استخدام الـ Dagger للحقن, وتستطيع عمل دالة public تريحك من هذا الامر تزودها بالـ id وتاتيك ببالمعلومات المراده.

وهكذا انشئنا كلاس Repository خاص بالـ Paging ياخد Paramters معين, سوف نقوم باستخدامه لاحقاً مع كل من الـ ViewModel و RecyclerView و Paging Adapter.

 

نهاية الدرس

فضلاً اذا اعجبك الدرس لاتنسى الضغظ على زر اعجبني ولنشر الفائدة قم بمشاركته مع من تحب. ولاتنسى تتبع الدرس حتى تطلع على التغييرات والتحديثات المتعلقه به مستقبلاً. وكذلك الامر بالنسبة للدورة من تتبع و اعجاب ومشاركة حتى يصلك جديد الدروس المتعلقه بها.

 

المصادر:

NewInstanceFactory

التعليقات (2)

Ali Mohamed Radwan:

@NonNull @Override public <T extends ViewModel> T create(@NonNull Class<T> modelClass) { return (T) new CardListViewModel(mApplication, mCardParentId); }  

ممكن حضرتك توضح اكتر الجزئيه دي 

Mohammad Laif:

الجزئية دي تعتبر تابع لنمط الـ Factory ونستخدمه لعملية الحقن للـ ViewModel حتى نستطيع ارسال لها البيانات بالحقن اذا احتجنا لذلك. تعتبر اسهل من استخدام مكتبة الـ Dagger 2 المعقدة, اذا واجهتك صعوبه في فهم هذا النمط قم بالبحث عنه فله بعض الدروس المختصه به باستخدام المصطلحات: AndroidViewModel و ViewModelProvider.

كما يوجد في هذا الدرس بقية اسماء الانماط (بشكل عام) المستخدمه: المتطلبات (Dependencies and Software Design Patterns).

  • نمط الـ Factory (سنستخدمة لعملية حقن يدوية للـ ViewModel بدلاً من مكتبة Dagger).

 

إما الدالة Create:

        @NonNull
        @Override
        public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
            return (T) new CardListViewModel(mApplication, mCardParentId);
        }

تساعد في انشاء نمط الـ Factory وهذا يساعدنا بعمل instantiate للـ Factory. ثم سنحقن هذا الـ Factory في الـ ViewModel لتمرير البيانات (البيانات التي نريد تمريرها للـ ViewModel هنا هي mCardParentId و application context). كما سنرى في الدرس القادم استخدام الـ ViewModel مع الـ Paging في الـ Activity:

انشاء الـ Factory ووضع له البيانات (يأخد Application Context و card parent id):

CardListViewModel.Factory factory = new CardListViewModel.Factory(getApplication(), mCardParentId);

حقن هذا الـ Factory في هذه الـ ViewModel:

mCardListViewModel = ViewModelProviders.of(this, factory).get(CardListViewModel.class);

وبهذا الشكل قمنا بتمرير بيانات الى الـ ViewModel اثناء عمل init لها.

 

اذا كنت لاتريد تمرير بيانات او اي شئ  للـ ViewModel تستطيع الاستغناء عن الحقن وعمل extends للكلاس ViewModel بدلاً من كلاس AndroidViewModel  عند انشاء كلاسك الـ ViewModel كما هو مبين في اول خطوة.

ايضاً في الدرس السابق انشاء الـ ViewModel بـ LiveData لم نحتج الى تمرير بيانات فلاداعي للـ Factory.

اخيراً اذا كنت تريد تمرير بيانات للـ ViewModel فلاتوجد الا طريقة الحقن سواء يدوياً بإستخدام نمط الـ Factory كما جاء في هذا الدرس, او من خلال استخدام مكتبة الـ Dagger 2.

 

لايوجد لديك حساب في عالم البرمجة؟

تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !