استخدام الـ ViewModel مع الـ LiveData في الـ Activity

Mohammad Laifمنذ 5 سنوات

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

في هذا الدرس سنتعلم كيفية استخدام الـ ViewModel صاحبة الـ LiveData في الـ Activity.

 

ماذا ستقرئ في هذا الدرس؟

  • كلاس Adapter عادي.
  • طريقة استخدام ViewModel في الـ RecyclerView لجلب البيانات.
  • طرق مختلفة لإستخدام الـ ViewModel كاستخدامها للحفظ والحذف والتحديث.

 

ماذا سننشئ؟

  • Adapter عادي لعناصر الـ Subject.

 

كلاس الـ Adapter:

package com.mzdhr.flashcards.adapter;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.mzdhr.flashcards.R;
import com.mzdhr.flashcards.database.entity.SubjectEntity;

import java.util.List;

public class SubjectListAdapter extends RecyclerView.Adapter<SubjectListAdapter.SubjectViewHolder> {

    private final LayoutInflater mInflater;
    private List<SubjectEntity> mSubjectEntities;    // Cached

    public SubjectListAdapter(Context context) {
        mInflater = LayoutInflater.from(context);
    }


    @NonNull
    @Override
    public SubjectViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View itemView = mInflater.inflate(R.layout.list_item_subject, parent, false);
        return new SubjectViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(@NonNull SubjectListAdapter.SubjectViewHolder holder, final int position) {
        if (mSubjectEntities != null) {
            SubjectEntity currentSubjectEntity = mSubjectEntities.get(position);
            holder.subjectTitleTextView.setText(currentSubjectEntity.getTitle());

            // Hook our custom click item listener to the item view.
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (mOnItemClickListener != null) {
                        mOnItemClickListener.ItemClicked(v, position);
                    }
                }
            });
        }
    }

    public void setSubjectEntities(List<SubjectEntity> subjectEntities) {
        mSubjectEntities = subjectEntities;
        notifyDataSetChanged();
    }

    @Override
    public int getItemCount() {
        if (mSubjectEntities != null) {
            return mSubjectEntities.size();
        } else {
            return 0;
        }
    }

    /**
     * Method to get item by position.
     * @param position
     * @return
     */
    @Nullable
    public SubjectEntity getItem(int position) {
        return mSubjectEntities.get(position);
    }


    /**
     * Custom click item listener.
     */
    onItemClickListener mOnItemClickListener;

    public void setClickListener(onItemClickListener itemClickListener) {
        mOnItemClickListener = itemClickListener;
    }

    public interface onItemClickListener {
        void ItemClicked(View v, int position);
    }


    /**
     * View Holder Class
     */
    class SubjectViewHolder extends RecyclerView.ViewHolder{
        private final TextView subjectTitleTextView;

        private SubjectViewHolder(View itemView) {
            super(itemView);
            subjectTitleTextView = itemView.findViewById(R.id.subject_title_textView);
        }
    }
}

تعقيب:

كلاس ادابتر عادية سوى انني استخدمت الدالة setSubjectEntities حتى ازود هذا الادابتر بالبيانات.

 

طريقة استخدام الـ ViewModel في الـ RecylerView

نقوم بتجهيز الـ Adapter و الـ RecyclerView كالعادة هكذا:

final SubjectListAdapter adapter = new SubjectListAdapter(this);
final RecyclerView recyclerView = findViewById(R.id.subject_list_recyclerView);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));

 

نقوم بأنشاء حقل للـ ViewModel:

private SubjectListViewModel mSubjectListViewModel;

 

نقوم بعمل init لها:

mSubjectListViewModel = ViewModelProviders.of(this).get(SubjectListViewModel.class);

لاحظ اننا استخدمنا ViewModelProviders للقيام بذلك (وذلك يعود الى ان الـ ViewModel تم انشائها باستخدام الـ Reflection).

 

نقوم باستخدام دالتنا getAllSubjects (هذه دالة الـ Query) حتى نأتي بالـ LiveData ثم نلحقها بـ Observer ونستخدم دالته onChanged لإعطاء الـ Adapter بالبيانات.

mSubjectListViewModel.getAllSubjects().observe(this, new Observer<List<SubjectEntity>>() {
    @Override
    public void onChanged(@Nullable List<SubjectEntity> subjectEntities) {
        adapter.setSubjectEntities(subjectEntities);
    }
});

 

طرق استخدام الـ ViewModel اخرى

استخدم الـ ViewModel لحفظ البيانات تكون على الشكل التالي:

Random random = new Random();
int n = random.nextInt(1000) + 1;
mSubjectListViewModel.insert(new SubjectEntity("Random subject number " + n, new Date(), 1));

 لاحظ بالسطر الاخير هو المغزى, قمنا باستخدام دالتنا insert لحفظ العنصر في قاعدة البيانات. وكذلك بالنسبة لباقي الدوال كالحذف وغيرها. الا في حالة الـ Update فأنت تحتاج لتزويد الدالة برقم الـ id الخاص بالعنصر الذي تريد تحديثه (كما فعلنا في الدرس السابق من الاختبارات).

 

لتحديث البيانات

SubjectEntity subjectEntity = new SubjectEntity("Math", new Date(), 1);
mSubjectListViewModel.updateSubject(new SubjectEntity(1, "Mathematics", subjectEntity.getDate(),

هنا يجب علينا استخدام Constructor الـ Room (ليس الـ Constructor الخاص بنا) ونقوم بأنشاء عنصر جديد باستخدامه, ويكون به رقم الـ id من جدول قاعدة البيانات لذلك العنصر المراد تحديثه وايضاً القيم المتغيره ونقوم باستخدام القيم التي لم يجري عليها اي تعديل من العنصر السابق.

من اين احصل على رقم الـ id؟

في مثالنا هذا قمنا باستخدام الرقم ١ لان لايوجد الا هذا العنصر بقاعدة البيانات (هل تذكر autoGenerate للـ id في كلاس الـ SubjectEntity). ولكن تستطيع الغاء ميزة الـ autoGenerate واستبدالة بشئ من عندك حتى تعرف ارقام عناصرك بقاعدة البيانات. وايضاً تستطيع معرفة الرقم الخاص بالعنصر بعد حفظة (مثال استخدام getId بداخل الـ onChange على العنصر). وتستطيع ايضاً جعل دالة الـ insert في كلاس الـ SubjectDao تقوم بارجاع رقم id بعد حفظ العنصر بقاعدة البيانات و -1 عند الفشل. واخيراً في مقدورك عمل دالة Query تقوم بالبحث عن عنصر ما وترجع رقم الـ id الخاص به.

 

ولكن في بعض الاحيان نحتاج الى استخدام Paging (عندما يكون لدينا كم هائل من البيانات المراد عرضهم في الـ RecyclerView خاصة وان كان الامر يتعلق بالشبكة العنكبوتية) ففي الدرس القادم سوف نرى كيفية انشاء adapter متوافق مع الـ Paging واللوازم الذي يحتاجها. وايضاً كيفية عمل Factory واستخدامة لتمرير الـ Paramters الى الـ ModelView.

 

نهاية الدرس

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

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

Ali Mohamed Radwan:

حضرتك هنا مش كاتب الكود بتاع الديزاين ليه ؟

Mohammad Laif:

شكراً اخي على التنبيه, المشروع موجود على حسابي بالـ Github ولكن كان بالغلط Private تم تعديله الى Public ووضع رابط له في الدرس تطبيق اندرويد للبطاقات التعليمية (Flash Cards). او تستطيع الوصول له من خلال الرابط المباشر FlashCards. تستطيع تصفحه ورؤية جميع الاكواد.

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

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