ملئ قاعدة البيانات الـ Room ببيانات جاهزه للمستخدم

Mohammad Laifمنذ سنة

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

في هذا الدرس سنتعلم كيفية ملئ قاعدة البيانات الـ Room ببيانات تظهر للمستخدم عند تثبيت التطبيق لإول مره.

 

ماذا سننشئ؟

  • انشاء Callback للـ Room.
  • انشاء كلاس PopulateDbAsync.

 

انشاء Callback للـ Room
في كلاس الـ AppDatabase للدرس السابقه نقوم بانشاء حقل من نوع RoomDatabase.Callback ثم نقوم بعمل Override للدوال المصاحبه مع هذا الـ Callback:

private static RoomDatabase.Callback sRoomDatabaseCallback = new RoomDatabase.Callback() {
    @Override
    public void onCreate(@NonNull SupportSQLiteDatabase db) {
        super.onCreate(db);
    }

    @Override
    public void onOpen(@NonNull SupportSQLiteDatabase db) {
        super.onOpen(db);
    }
};

تعقيب:

  • الدالة onCreate تقوم بالعمل فقط مره واحده وهي عند انشاء قاعدة البيانات (اي تعمل مره واحده عند تثبيت التطبيق وفتحه من قبل المستخدم). وهي التي سوف نستخدمها.
  • الدالة onOpen تعمل في كل مره يقوم التطبيق بالتعامل مع قاعدة البيانات (اي تعمل في كل مره عند تشغيل التطبيق).

 

انشاء كلاس PopulateDbAsync
نعمل كلاس AsyncTask بداخل كلاس الـ AppDatabase ونضع بها حقول للـ DAO على الشكل التالي:

private static class PopulateDbAsync extends AsyncTask<Void, Void, Void> {
    private final SubjectDao mSubjectDao;
    private final CardDao mCardDao;
}

 

ننشئ Constractor لها لتهيئة الـ DAO على النحو التالي:

PopulateDbAsync(AppDatabase db) {
    mSubjectDao = db.subjectDao();
    mCardDao = db.cardDao();
}

 

نعمل Override للدالة doInBackground ومن خلالها نقوم بصنع العناصر وتعبئة قاعدة البيانات:

@Override
protected Void doInBackground(final Void... params) {
    SubjectEntity subjectEntity01 = new SubjectEntity("Math", new Date(), 1);
    SubjectEntity subjectEntity02 = new SubjectEntity("Computer", new Date(), 1);
    mSubjectDao.insertSubject(subjectEntity01);
    mSubjectDao.insertSubject(subjectEntity02);
    return null;
}

 

نقوم بتشغيل هذه الكلاس بداخل دالة onCreate في الـ RoomDatabase.Callback وذلك بانشاء عنصر جديد منها وعمل execute له:

private static RoomDatabase.Callback sRoomDatabaseCallback = new RoomDatabase.Callback() {
    @Override
    public void onCreate(@NonNull SupportSQLiteDatabase db) {
        super.onCreate(db);
        new PopulateDbAsync(sInstance).execute();
    }

    @Override
    public void onOpen(@NonNull SupportSQLiteDatabase db) {
        super.onOpen(db);
    }
};

 

نقوم بإضافة الـ RoomDatabase.Callback الى قاعدة البيانات في دالة getInstance التي عملناها في الدرس السابق قبل بناء قاعدة البيانات على النحو التالي:

public static AppDatabase getInstance(Context context) {
    if (sInstance == null) {
        synchronized (LOCK) {
            Log.d(TAG, "getInstance: Creating a new database instance");
            sInstance = Room.databaseBuilder(
                    context.getApplicationContext(),
                    AppDatabase.class,
                    AppDatabase.DATABASE_NAME)
                    .addCallback(sRoomDatabaseCallback) // to populate database
                    .build();
        }
    }
    Log.d(TAG, "getInstance: Getting the database instance, no need to recreated it.");
    return sInstance;
}

 

لتصبح كلاس قاعدة البيانات AppDatabase بشكل كامل على هذا النحو:

package com.mzdhr.flashcards.database;

import android.arch.persistence.db.SupportSQLiteDatabase;
import android.arch.persistence.room.Database;
import android.arch.persistence.room.Room;
import android.arch.persistence.room.RoomDatabase;
import android.arch.persistence.room.TypeConverters;
import android.content.Context;
import android.os.AsyncTask;
import android.support.annotation.NonNull;
import android.util.Log;

import com.mzdhr.flashcards.database.converter.DateConverter;
import com.mzdhr.flashcards.database.dao.CardDao;
import com.mzdhr.flashcards.database.dao.SubjectDao;
import com.mzdhr.flashcards.database.entity.CardEntity;
import com.mzdhr.flashcards.database.entity.SubjectEntity;

import java.util.Date;

@Database(entities = {SubjectEntity.class, CardEntity.class}, version = 1, exportSchema = false)
@TypeConverters(DateConverter.class)
public abstract class AppDatabase extends RoomDatabase {

    private static final String TAG = AppDatabase.class.getSimpleName();
    private static final Object LOCK = new Object();
    private static final String DATABASE_NAME = "flashcardsdb";
    private static AppDatabase sInstance;

    public static AppDatabase getInstance(Context context) {
        if (sInstance == null) {
            synchronized (LOCK) {
                Log.d(TAG, "getInstance: Creating a new database instance");
                sInstance = Room.databaseBuilder(
                        context.getApplicationContext(),
                        AppDatabase.class,
                        AppDatabase.DATABASE_NAME)
                        .addCallback(sRoomDatabaseCallback) // to populate database
                        .build();
            }
        }
        Log.d(TAG, "getInstance: Getting the database instance, no need to recreated it.");
        return sInstance;
    }

    public abstract SubjectDao subjectDao();
    public abstract CardDao cardDao();


    /**
     * Populate Database Section
     */
    private static RoomDatabase.Callback sRoomDatabaseCallback = new RoomDatabase.Callback() {
        @Override
        public void onCreate(@NonNull SupportSQLiteDatabase db) {
            super.onCreate(db);
            new PopulateDbAsync(sInstance).execute();
        }

        @Override
        public void onOpen(@NonNull SupportSQLiteDatabase db) {
            super.onOpen(db);
        }
    };
    

    private static class PopulateDbAsync extends AsyncTask<Void, Void, Void> {

        private final SubjectDao mSubjectDao;
        private final CardDao mCardDao;

        PopulateDbAsync(AppDatabase db) {
            mSubjectDao = db.subjectDao();
            mCardDao = db.cardDao();
        }

        @Override
        protected Void doInBackground(final Void... params) {
            SubjectEntity subjectEntity01 = new SubjectEntity("Math", new Date(), 1);
            SubjectEntity subjectEntity02 = new SubjectEntity("Computer", new Date(), 1);
            mSubjectDao.insertSubject(subjectEntity01);
            mSubjectDao.insertSubject(subjectEntity02);
            return null;
        }
    }
}


وهكذا عند تشغيل المستخدم لهذا التطبيق سوف يرى مادتين Math و Computer قد تم اضافتهم من قبل المبرمج.


نهاية الدرس

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


المصادر:

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

Mohammad Laif:

هناك طريقة اخرى لملئ قاعدة البيانات بإستخدام الـ Executors افضل من استخدام كلاس الـ AsyncTask.

في الرابط: ماهو نمط الـ Thread Pools (الـ Executors).

 

صلتح:

ي اخي اريد مساعدتك انا سويت نفس خطواتك تماما وملئت قاعده البيانات لكن الحين مابي استخدم الـ livadata والمكونات الثاني ابغى استخدم قاعده البيانات مع الاكتفتي ممكن تساعدني ب اسهل طريقة ؟!

Mohammad Laif:

اهلا اخي

تستطيع تخطي الطبقة "المستودع" و "Paging". المهم هو Dao و LIveData و ViewModel حتى لاتحدث معك مشاكل. ولكن من الافضل كبدايه عدم تخطي اي طبقات حتى تتضح لك الصوره الكليه عندما تنتهي. ثم بعد ذلك تستطيع تخطي اي من الطبقات على راحتك.

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

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