يشكّل هذا الدرس التطبيقي جزءًا من الدورة التدريبية لأساسيات Android Kotlin. ستحصل على أقصى قيمة ممكنة من هذه الدورة التدريبية إذا كنت تستخدم الدروس التطبيقية حول الترميز بشكل متسلسل. يتم إدراج جميع الدروس التطبيقية حول ترميز الدورات التدريبية في الصفحة المقصودة لدروس الترميز Android Kotlin Fundamentals.
مقدمة
تتضمّن معظم التطبيقات بيانات يجب الاحتفاظ بها، حتى بعد إغلاق المستخدم للتطبيق. على سبيل المثال، قد يخزِّن التطبيق قائمة تشغيل أو مستودعًا لعناصر اللعبة أو سجلات للنفقات أو الدخل أو كتالوجًا لمجموعات نجمية أو بيانات عن النوم بمرور الوقت. ويمكنك عادةً استخدام قاعدة بيانات لتخزين البيانات الدائمة.
Room
هي مكتبة قاعدة بيانات تمثل جزءًا من Jetpack لنظام التشغيل Android. يتولى Room
الكثير من مهام إعداد قاعدة البيانات وضبطها، كما يسمح لتطبيقك بالتفاعل مع قاعدة البيانات باستخدام استدعاءات الوظائف العادية. في الخيارات المتقدمة، Room
هو طبقة تجريدية أعلى قاعدة بيانات SQLite. مصطلحات Room
's وبنية طلب البحث لطلبات البحث الأكثر تعقيدًا، اتبع نموذج SQLite.
توضّح الصورة أدناه مدى توافق قاعدة بيانات Room
مع البنية العامة المقترحة في هذه الدورة التدريبية.
ما يجب معرفته
ويجب أن تكون على دراية بما يلي:
- إنشاء واجهة مستخدم أساسية لأحد تطبيقات Android
- استخدام الأنشطة والأجزاء والعروض.
- الانتقال بين الأجزاء واستخدام Smart Args (مكوّن إضافي في Gradle) لتمرير البيانات بين الأجزاء.
- عرض النماذج ومصانع نماذج العرض و
LiveData
ومراصدها يمكنك الاطّلاع على المواضيع التالية حول المكوّنات المعمارية في درس تطبيقي سابق حول الترميز في هذه الدورة التدريبية. - فهم أساسي لقواعد بيانات SQL ولغة SQLite. اطّلِع على SQLite Primer للحصول على نظرة عامة سريعة أو تذكير.
ما ستتعرَّف عليه
- كيفية إنشاء قاعدة بيانات
Room
والتفاعل معها للاحتفاظ بالبيانات. - كيفية إنشاء فئة بيانات تحدّد جدولاً في قاعدة البيانات.
- كيفية استخدام كائن الوصول إلى البيانات (DAO) لربط وظائف Kotlin بطلبات بحث SQL.
- كيفية اختبار ما إذا كانت قاعدة البيانات تعمل أم لا.
الإجراءات التي ستنفذّها
- إنشاء قاعدة بيانات لتطبيق
Room
بواجهة لبيانات النوم ليلاً. - اختبر قاعدة البيانات باستخدام الاختبارات المقدمة.
في هذا الدرس التطبيقي حول الترميز، تُنشئ جزء قاعدة البيانات من تطبيق يتتبَّع جودة النوم. يستخدم التطبيق قاعدة بيانات لتخزين بيانات النوم بمرور الوقت.
يحتوي التطبيق على شاشتين، تمثلهما الأجزاء، كما هو موضّح في الشكل التالي.
تحتوي الشاشة الأولى، الموضحة على اليمين، على أزرار لبدء التتبع وإيقافه. تعرض الشاشة جميع بيانات النوم للمستخدم. يعمل الزر محو على حذف جميع البيانات التي جمعها التطبيق للمستخدم نهائيًا.
الشاشة الثانية، التي تظهر على اليسار، مخصّصة لاختيار تقييم جودة النوم. في التطبيق، يتم تمثيل التقييم رقميًا. لأغراض التطوير، يعرض التطبيق كلاً من رموز الوجه والمعادلات الرقمية لها.
تكون خطوات المستخدم على النحو التالي:
- يفتح المستخدم التطبيق وتظهر له شاشة تتبُّع النوم.
- ينقر المستخدم على الزر ابدأ. يسجِّل هذا العمود وقت البدء ويعرضه. يكون زر البدء غير مفعّل، والزر إيقاف مفعّل.
- ينقر المستخدم على الزر إيقاف. ويتم تسجيل وقت الانتهاء وفتح شاشة جودة النوم.
- ويختار المستخدم رمز جودة النوم. ويتم إغلاق الشاشة، كما تعرض شاشة التتبُّع وقت انتهاء النوم وجودة النوم. الزر إيقاف غير مفعّل والزر ابدأ مفعّل. التطبيق جاهز لليلة أخرى.
- يتم تفعيل الزر محو عند توفّر بيانات في قاعدة البيانات. عندما ينقر المستخدم على الزر محو، يتم محو جميع بياناته بدون اللجوء إلى الخطأ - لا تظهر هذه الرسالة&كذلك، هل أنت متأكد؟
يستخدم هذا التطبيق بنية مبسطة، كما هو موضح أدناه في سياق البنية الكاملة. يستخدم التطبيق المكونات التالية فقط:
- وحدة تحكُّم واجهة المستخدم
- عرض النموذج و
LiveData
- قاعدة بيانات الغرفة
الخطوة 1: تنزيل تطبيق بدء التشغيل وتشغيله
- نزِّل تطبيق TrackMySleepquality-Starter من GitHub.
- إنشاء التطبيق وتشغيله. يعرض التطبيق واجهة المستخدم للجزء
SleepTrackerFragment
، ولكن بدون بيانات. الأزرار لا تستجيب للنقرات.
الخطوة 2: فحص تطبيق إجراء التفعيل
- الاطّلاع على ملفات Gradle:
- ملف Gradle للمشروع
في ملفbuild.gradle
على مستوى المشروع، لاحظ المتغيرات التي تحدد إصدارات المكتبة. تعمل الإصدارات المُستخدَمة في تطبيق المبتدئين معًا بشكلٍ جيد، كما أنها تعمل بشكل جيد مع هذا التطبيق. وعند الانتهاء من هذا الدرس التطبيقي حول الترميز، قد يطلب منك "استوديو Android" تحديث بعض الإصدارات. يرجع الأمر إليك عما إذا كنت تريد تحديث الإصدارات الموجودة في التطبيق أو البقاء فيها. إذا واجهت أخطاء "strange" مجمّعة، جرِّب استخدام مجموعة إصدارات المكتبة التي يستخدمها تطبيق الحل النهائي. - ملف Gradle الخاص بالوحدة. لاحِظ أنّها تعتمد على جميع الارتباطات في مكتبات Android Jetpack، بما في ذلك
Room
واعتماديات الكوروتين.
- ألقِ نظرة على الحزم وواجهة المستخدم. تم تنظيم التطبيق حسب الوظائف. تحتوي الحزمة على ملفات عناصر نائبة حيث يمكنك إضافة الرمز إلى هذه السلسلة من الدروس التطبيقية حول الترميز.
database
حزمة، لكل الرموز المتعلقة بقاعدة بياناتRoom
.- تحتوي حزمتا
sleepquality
وsleeptracker
على الجزء ونموذج العرض ومصنع نموذج العرض لكل شاشة.
- يمكنك إلقاء نظرة على ملف
Util.kt
الذي يحتوي على وظائف للمساعدة في عرض بيانات جودة النوم. تم التعليق على بعض الرموز لأنها تشير إلى نموذج عرض تنشئه لاحقًا. - اطّلِع على مجلد androidTest (
SleepDatabaseTest.kt
). وستستخدم هذا الاختبار للتحقّق من أن قاعدة البيانات تعمل على النحو المطلوب.
في نظام التشغيل Android، يتم تمثيل البيانات في فئات البيانات، ويتم الوصول إلى البيانات وتعديلها باستخدام طلبات الوظائف. ومع ذلك، في عالم قاعدة البيانات، تحتاج إلى الكيانات وطلبات البحث.
- يمثل الكيان كائنًا أو مفهومًا وخصائصه لتخزينها في قاعدة البيانات. تحدد فئة الكيان جدولاً، ويمثّل كل مثيل لذلك الصف صفًا في الجدول. تحدد كل خاصية عمودًا. في تطبيقك، سيحتفظ الكيان بمعلومات حول الليل.
- طلب البحث هو طلب للحصول على بيانات أو معلومات من جدول قاعدة بيانات أو مجموعة من الجداول، أو طلب تنفيذ إجراء على البيانات. ومن طلبات البحث الشائعة، الحصول على الكيانات وإدراجها وتعديلها. على سبيل المثال، يمكنك طلب البحث عن جميع ليالي النوم المسجّلة، مرتّبة حسب وقت البدء.
وتنجز Room
جميع المهام الصعبة للحصول على من فئات بيانات Kotlin إلى الكيانات التي يمكن تخزينها في جداول SQLite، ومن بيانات الدالة إلى طلبات بحث SQL.
يجب تحديد كل كيان كفئة بيانات تتضمن تعليقات توضيحية، والتفاعلات كواجهة تتضمن تعليقات توضيحية، وكائن الوصول إلى البيانات (DAO). يستخدم Room
هذه الصفوف التي تم التعليق عليها لإنشاء الجداول في قاعدة البيانات، وطلبات البحث التي تعمل على قاعدة البيانات.
الخطوة 1: إنشاء كيان SleepNight
في هذه المهمة، يمكنك تحديد ليلة واحدة من النوم كفئة بيانات تتضمّن تعليقات توضيحية.
عند تسجيل ليلة واحدة للنوم، عليك تسجيل وقت البدء ووقت الانتهاء وتقييم الجودة.
ويجب أيضًا توفّر بطاقة تعريف لتحديد الليل بشكل فريد.
- في حزمة
database
، ابحث عن ملفSleepNight.kt
وافتحه. - يمكنك إنشاء فئة بيانات
SleepNight
باستخدام معلّمات لرقم تعريف ووقت البدء (بالمللي ثانية) ووقت الانتهاء (بالمللي ثانية) وتقييم رقمي لجودة النوم.
- يجب إعداد
sleepQuality
، لذا يجب ضبطه على-1
، ما يشير إلى أنّه لم يتم جمع أي بيانات للجودة. - وعليك أيضًا إعداد وقت الانتهاء. اضبطه على وقت البدء للإشارة إلى عدم تسجيل أي وقت انتهاء بعد.
data class SleepNight(
var nightId: Long = 0L,
val startTimeMilli: Long = System.currentTimeMillis(),
var endTimeMilli: Long = startTimeMilli,
var sleepQuality: Int = -1
)
- قبل الإعلان عن الصف الدراسي، يمكنك إضافة تعليقات توضيحية إلى فئة البيانات باستخدام
@Entity
. أدخِل اسمًا للجدولdaily_sleep_quality_table
. ويكون وسيطةtableName
اختيارية، ولكن ننصح بها. يمكنك البحث عن وسيطات أخرى في المستندات.
في حال المطالبة بذلك، يمكنك استيرادEntity
وجميع التعليقات التوضيحية الأخرى من المكتبةandroidx
.
@Entity(tableName = "daily_sleep_quality_table")
data class SleepNight(...)
- لتحديد
nightId
باعتباره المفتاح الأساسي، يمكنك إضافة تعليقات توضيحية إلى السمةnightId
باستخدام@PrimaryKey
. اضبط المعلمةautoGenerate
علىtrue
بحيث تُنشئRoom
رقم التعريف لكل كيان. وهذا يضمن أن يكون رقم التعريف لكل ليلة فريدًا.
@PrimaryKey(autoGenerate = true)
var nightId: Long = 0L,...
- يمكنك إضافة تعليقات توضيحية إلى الخصائص المتبقية باستخدام
@ColumnInfo
. يمكنك تخصيص أسماء المواقع باستخدام المعلَمات كما هو موضح أدناه.
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "daily_sleep_quality_table")
data class SleepNight(
@PrimaryKey(autoGenerate = true)
var nightId: Long = 0L,
@ColumnInfo(name = "start_time_milli")
val startTimeMilli: Long = System.currentTimeMillis(),
@ColumnInfo(name = "end_time_milli")
var endTimeMilli: Long = startTimeMilli,
@ColumnInfo(name = "quality_rating")
var sleepQuality: Int = -1
)
- أنشئ الرمز وشغِّله للتأكُّد من خلوِّه من الأخطاء.
في هذه المهمة، يمكنك تحديد كائن الوصول إلى البيانات (DAO). على نظام التشغيل Android، توفِّر خدمة DAO طرقًا ملائمة لإدراج قاعدة البيانات وحذفها وتعديلها.
عند استخدام قاعدة بيانات Room
، يمكنك تشغيل طلب بحث في قاعدة البيانات من خلال تحديد استدعاءات Kotlin واستدعاؤها. ويتم ربط وظائف Kotlin هذه بطلبات بحث SQL. ويمكنك تحديد عمليات الربط هذه في "إحصاءات Google" باستخدام التعليقات التوضيحية، وسينشئ Room
الرمز اللازم.
يمكنك التفكير في استخدام مُعرّف البيانات الرقمي (DAO) على أنه واجهة مخصّصة للوصول إلى قاعدة البيانات الخاصة بك.
لإجراء عمليات قاعدة البيانات الشائعة، توفر مكتبة Room
تعليقات توضيحية مريحة، مثل @Insert
و@Delete
و@Update
. بالنسبة إلى كل شيء آخر، هناك تعليق توضيحي من @Query
. يمكنك كتابة أي طلب بحث متوافق مع SQLite.
وكمكافأة إضافية، عندما تُنشئ طلبات البحث في "استوديو Android"، تتحقّق برامج التجميع من طلبات بحث SQL بحثًا عن أخطاء في البنية.
يجب أن يكون بإمكانك تنفيذ الإجراءات التالية في قاعدة بيانات تتبُّع النوم لأمسيات النوم:
- إدراج ليالٍ جديدة.
- تعديل ليلة حالية لتعديل وقت الانتهاء وتقييم الجودة.
- الحصول على ليلة معيّنة استنادًا إلى مفتاحها.
- الحصول على جميع الليالي حتى تتمكّن من عرضها
- الحصول على أحدث ليلة.
- احذف جميع الإدخالات في قاعدة البيانات.
الخطوة 1: إنشاء SleepDatabase DAO
- في الحزمة
database
، افتحSleepDatabaseDao.kt
. - لاحظ أن
interface
SleepDatabaseDao
تمت إضافة تعليقات توضيحية عليه باستخدام@Dao
. يجب إضافة تعليقات توضيحية إلى جميع أجهزة DAO بالكلمة الرئيسية@Dao
.
@Dao
interface SleepDatabaseDao {}
- داخل نص الواجهة، أضِف تعليقًا توضيحيًا من نوع
@Insert
. أسفل@Insert
، تتم إضافة الدالةinsert()
التي تستخدم مثيلEntity
الفئةSleepNight
كوسيطة لها.
هذا كل ما في الأمر. سينشئRoom
جميع الرموز اللازمة لإدراجSleepNight
في قاعدة البيانات. عند استدعاءinsert()
من رمز Kotlin، ينفذRoom
طلب SQL لإدراج الكيان في قاعدة البيانات. (ملاحظة: يمكنك استدعاء الدالة لأي شيء تريده).
@Insert
fun insert(night: SleepNight)
- أضِف تعليقًا توضيحيًا
@Update
مع دالةupdate()
لإحدىSleepNight
. الكيان الذي تم تحديثه هو الكيان الذي لديه المفتاح نفسه للكيان الذي تم تمريره. يمكنك تحديث بعض خصائص الكيان الأخرى أو جميعها.
@Update
fun update(night: SleepNight)
ليس هناك تعليق توضيحي ملائم للوظائف المتبقية، لذا عليك استخدام التعليق التوضيحي @Query
وتقديم طلبات بحث SQLite.
- أضِف تعليقًا توضيحيًا
@Query
مع دالةget()
يتضمّن وسيطةLong
key
ويعرض قيمةSleepNight
فارغة. سترى خطأً في المعلمة المفقودة.
@Query
fun get(key: Long): SleepNight?
- يتم توفير طلب البحث كمعلَمة سلسلة إلى التعليق التوضيحي. يمكنك إضافة معلمة إلى
@Query
. حوِّلString
إلى طلب بحث SQLite.
- اختيار جميع الأعمدة من
daily_sleep_quality_table
WHERE
تتطابقnightId
مع الوسيطة :key
.
يُرجى ملاحظة:key
. يمكنك استخدام تدوين النقطتين الرأسيتين في طلب البحث للإشارة إلى الوسيطات في الدالة.
("SELECT * from daily_sleep_quality_table WHERE nightId = :key")
- يمكنك إضافة
@Query
آخر باستخدام دالةclear()
وطلب بحث SQLite إلىDELETE
كل شيء منdaily_sleep_quality_table
. لا يحذف طلب البحث هذا الجدول نفسه.
يحذف التعليق التوضيحي@Delete
عنصرًا واحدًا، ويمكنك استخدام@Delete
وتقديم قائمة بالليالي لحذفها. عيب ذلك أنك تحتاج إلى استرجاع أو معرفة ما هو متوفّر في الجدول. يُعد التعليق التوضيحي@Delete
رائعًا لحذف إدخالات معيّنة، ولكنه غير فعّال لمحو جميع الإدخالات من الجدول.
@Query("DELETE FROM daily_sleep_quality_table")
fun clear()
- يمكنك إضافة
@Query
مع الدالةgetTonight()
. يمكنك عرضSleepNight
فارغًا من خلالgetTonight()
، بحيث يمكن للدالة معالجة الحالة التي يكون فيها الجدول فارغًا. (الجدول فارغ في البداية وبعد محو البيانات).
للحصول على "tonight" من قاعدة البيانات، اكتب طلب بحث SQL يعرض العنصر الأول من قائمة النتائج التي يتم طلبها حسبnightId
تنازليًا. استخدِمLIMIT 1
لعرض عنصر واحد فقط.
@Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC LIMIT 1")
fun getTonight(): SleepNight?
- أضِف
@Query
مع الدالةgetAllNights()
:
- اطلب من طلب SQLite عرض جميع الأعمدة من
daily_sleep_quality_table
، مرتبةً تنازليًا. - اطلب من
getAllNights()
عرض قائمة بالكياناتSleepNight
بصفتهاLiveData
. يحافظRoom
على تحديثLiveData
نيابةً عنك، ما يعني أنك لن تحتاج إلى الحصول على البيانات إلا مرة واحدة فقط. - قد تحتاج إلى استيراد
LiveData
منandroidx.lifecycle.LiveData
.
@Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC")
fun getAllNights(): LiveData<List<SleepNight>>
- على الرغم من أنك لن ترى أي تغييرات مرئية، يمكنك تشغيل تطبيقك للتأكد من عدم حدوث أخطاء.
في هذه المهمة، يمكنك إنشاء قاعدة بيانات Room
تستخدم Entity
وDAO اللذين أنشأتهما في المهمة السابقة.
يجب إنشاء صف مجرّد لصاحب قاعدة البيانات، مع إضافة تعليقات توضيحية إلى @Database
. تتضمن هذه الفئة طريقة واحدة تنشئ مثيلاً لقاعدة البيانات إذا لم تكن قاعدة البيانات متوفرة أو تعرض مرجعًا لقاعدة بيانات حالية.
يتطلّب الحصول على قاعدة بيانات Room
بعض الشيء، لذا إليك هذه العملية العامة قبل البدء باستخدام الرمز:
- أنشئ صفًا واحدًا (
public abstract
) يكونextends RoomDatabase
. تم تخصيص هذا الصف كصاحب قاعدة بيانات. الصف مجرد، لأنRoom
ينشئ التنفيذ من أجلك. - يمكنك إضافة تعليقات توضيحية إلى الصف
@Database
. في الوسيطات، أعلن عن الكيانات لقاعدة البيانات وحدّد رقم الإصدار. - داخل العنصر
companion
، حدّد طريقة مجردة أو خاصية تعرض السمةSleepDatabaseDao
. سينشئRoom
النص نيابةً عنك. - أنت تحتاج فقط إلى مثيل واحد من قاعدة بيانات
Room
للتطبيق بأكمله، لذا اجعلRoomDatabase
أحاديًا. - استخدم أداة إنشاء قاعدة بيانات
Room
's لإنشاء قاعدة البيانات فقط إذا لم تتوفر قاعدة البيانات. بخلاف ذلك، يمكنك عرض قاعدة البيانات الحالية.
الخطوة 1: إنشاء قاعدة البيانات
- في الحزمة
database
، افتحSleepDatabase.kt
. - في الملف، أنشِئ صف
abstract
باسمSleepDatabase
يمتد إلىRoomDatabase
.
يمكنك إضافة تعليق توضيحي إلى الصف باستخدام@Database
.
@Database()
abstract class SleepDatabase : RoomDatabase() {}
- سترى خطأً بشأن الكيانات ومَعلمات الإصدار غير المتوفّرة. يتطلب التعليق التوضيحي
@Database
عدة وسيطات، حتى تتمكنRoom
من إنشاء قاعدة البيانات.
- قدِّم السمة
SleepNight
باعتبارها العنصر الوحيد الذي يتضمّن قائمةentities
. - ضبط
version
كطريقة دفع1
كلما غيّرت المخطط، يجب زيادة رقم الإصدار. - اضبط
exportSchema
علىfalse
، بحيث لا يتم الاحتفاظ بالنُسخ الاحتياطية لسجلّ إصدارات المخطط.
entities = [SleepNight::class], version = 1, exportSchema = false
- تحتاج قاعدة البيانات إلى الحصول على معلومات عن DAO. داخل نص الصف الدراسي، أعلن عن القيمة المجرّدة التي تعرض
SleepDatabaseDao
. يمكن أن يكون لديك عدة علامات DAO.
abstract val sleepDatabaseDao: SleepDatabaseDao
- وأسفل ذلك، حدِّد كائن
companion
. يتيح الكائن المصاحب للعملاء الوصول إلى طرق إنشاء قاعدة البيانات أو الحصول عليها بدون إنشاء مثيل للصف. نظرًا لأن الغرض الوحيد من هذه الفئة هو توفير قاعدة بيانات، ليس هناك ما يدعو إلى إنشاء مثيل لها على الإطلاق.
companion object {}
- داخل الكائن
companion
، يمكنك تعريف متغيّر خاص قابل للإفراغINSTANCE
لقاعدة البيانات وإعداده علىnull
. سيحتفظ المتغيرINSTANCE
بمرجع في قاعدة البيانات، بعد إنشاء واحد. يساعدك ذلك على تجنُّب فتح الاتصالات بقاعدة البيانات بشكل متكرر، وهو أمر مكلف.
يمكنك إضافة تعليقات توضيحية إلى INSTANCE
باستخدام @Volatile
. لن يتم مطلقًا تخزين قيمة المتغير المتذبذب مؤقتًا، وسيتم إجراء جميع عمليات القراءة والقراءة من الذاكرة الرئيسية وإليها. يساعد ذلك على التأكد من أن قيمة INSTANCE
محدّثة دائمًا بالقيمة نفسها لجميع سلاسل المحادثات التي يتم تنفيذها. ويعني ذلك أنّ التغييرات التي تجريها سلسلة محادثات واحدة على INSTANCE
ستكون مرئية لجميع سلاسل المحادثات الأخرى على الفور، ولن تظهر لك رسالة مفادها أنّ كلاً من سلسلة المحادثات يؤدي إلى تعديل الكيان نفسه في ذاكرة التخزين المؤقت، ما قد يؤدي إلى حدوث مشكلة.
@Volatile
private var INSTANCE: SleepDatabase? = null
- أسفل
INSTANCE
، مع الاستمرار في داخل الكائنcompanion
، حدّدgetInstance()
طريقة باستخدام معلمةContext
التي ستحتاج إليها أداة إنشاء قواعد البيانات. عرض نوعSleepDatabase
ستظهر لك رسالة خطأ لأنgetInstance()
لا يعرض أي شيء حتى الآن.
fun getInstance(context: Context): SleepDatabase {}
- داخل
getInstance()
، أضِف كتلةsynchronized{}
. إدخالthis
حتى تتمكّن من الوصول إلى السياق.
من المحتمل أن تطلب سلاسل محادثات متعددة إنشاء مثيل قاعدة بيانات في الوقت نفسه، ما يؤدي إلى إنشاء قاعدتي بيانات بدلاً من قاعدة واحدة. من غير المحتمل أن تحدث هذه المشكلة في نموذج التطبيق هذا، ولكنها ممكنة في تطبيق أكثر تعقيدًا. عند إلحاق الرمز لإدخال قاعدة البيانات فيsynchronized
، لا يمكن إدخال سوى سلسلة محادثات واحدة فقط للتنفيذ في كل مرة، ما يضمن إعداد قاعدة البيانات مرة واحدة فقط.
synchronized(this) {}
- داخل الكتلة المتزامنة، انسخ القيمة الحالية
INSTANCE
إلى المتغير المحليinstance
. وهذا للاستفادة من ميزة البث الذكي التي لا تتوفر إلا للمتغيرات المحلية.
var instance = INSTANCE
- داخل كتلة
synchronized
،return instance
في نهاية المجموعةsynchronized
. تجاهل الخطأ "غير متطابق في نوع الإرجاع"، ولن تظهر لك أي قيم فارغة بعد الانتهاء.
return instance
- في أعلى عبارة
return
، أضِف عبارةif
للتحقق مما إذا كانت السياسةinstance
فارغة، أي ليست هناك قاعدة بيانات حتى الآن.
if (instance == null) {}
- إذا كانت
instance
هيnull
، استخدِم أداة إنشاء قواعد البيانات للحصول على قاعدة بيانات. في نص عبارةif
، يمكنك استدعاءRoom.databaseBuilder
وتقديم السياق الذي أدخلته وفئة قاعدة البيانات واسم لقاعدة البياناتsleep_history_database
. لإزالة الخطأ، سيكون عليك إضافة استراتيجية نقل البيانات وbuild()
في الخطوات التالية.
instance = Room.databaseBuilder(
context.applicationContext,
SleepDatabase::class.java,
"sleep_history_database")
- أضِف استراتيجية نقل البيانات المطلوبة إلى "أداة الإنشاء". استخدام
.fallbackToDestructiveMigration()
.
عادةً ما تحتاج إلى توفير عنصر نقل بيانات مع استراتيجية نقل البيانات عند تغيُّر المخطط. كائن الترحيل هو كائن يحدد كيفية نقل جميع الصفوف باستخدام المخطط القديم وتحويلها إلى صفوف في المخطط الجديد، بحيث لا يتم فقدان أي بيانات. تتجاوز عملية نقل البيانات نطاق هذا الدرس التطبيقي حول الترميز. يتمثل أحد الحلول البسيطة في إتلاف قاعدة البيانات وإعادة إنشائها، مما يعني فقدان البيانات.
.fallbackToDestructiveMigration()
- أَخِيرًا، اتَّصِلْ بِـ
.build()
.
.build()
- تحديد
INSTANCE = instance
كخطوة نهائية داخل كشفif
.
INSTANCE = instance
- ويجب أن يظهر الرمز النهائي بالشكل التالي:
@Database(entities = [SleepNight::class], version = 1, exportSchema = false)
abstract class SleepDatabase : RoomDatabase() {
abstract val sleepDatabaseDao: SleepDatabaseDao
companion object {
@Volatile
private var INSTANCE: SleepDatabase? = null
fun getInstance(context: Context): SleepDatabase {
synchronized(this) {
var instance = INSTANCE
if (instance == null) {
instance = Room.databaseBuilder(
context.applicationContext,
SleepDatabase::class.java,
"sleep_history_database"
)
.fallbackToDestructiveMigration()
.build()
INSTANCE = instance
}
return instance
}
}
}
}
- إنشاء الرمز وتشغيله
لديك الآن كل العناصر الأساسية للعمل مع قاعدة بيانات Room
. يتم تجميع هذا الرمز وتشغيله، ولكن ليست لديك طريقة لمعرفة ما إذا كان يعمل فعليًا أم لا. لذا، الوقت مناسب لإضافة بعض الاختبارات الأساسية.
الخطوة 2: اختبار SleepDatabase
في هذه الخطوة، يمكنك تشغيل الاختبارات المقدمة للتحقق من عمل قاعدة البيانات. ويساعد ذلك على ضمان عمل قاعدة البيانات قبل إنشائها. الاختبارات المقدمة أساسية. بالنسبة إلى تطبيق إنتاج، يمكنك ممارسة جميع الوظائف وطلبات البحث في جميع مشاهِدي البيانات DAO.
يحتوي تطبيق إجراء التفعيل على مجلد androidTest. يحتوي مجلد androidTest هذا على اختبارات الوحدات التي تتضمن أدوات Android، وهي طريقة رائعة للتصريح بأن الاختبارات تحتاج إلى إطار عمل Android، لذا عليك إجراء الاختبارات على جهاز فعلي أو افتراضي. ويمكنك أيضًا إنشاء اختبارات الوحدة الخالصة التي لا تتضمّن إطار عمل Android وتنفيذها.
- في "استوديو Android"، في مجلد androidTest، افتح ملف SleepDatabaseTest.
- لإلغاء تعليق الرمز، اختَر جميع الرموز التي تم التعليق عليها واضغط على اختصار لوحة المفاتيح
Cmd+/
أوControl+/
. - ألقِ نظرة على الملف.
في ما يلي شرح سريع لرمز الاختبار لأنّه يشكّل جزءًا آخر من الرمز يمكنك إعادة استخدامه:
SleepDabaseTest
هو صف اختباري.- يحدّد التعليق التوضيحي
@RunWith
أنّه مخصّص للاختبار، وهو البرنامج الذي يُعِدّ الاختبارات وينفّذها. - أثناء الإعداد، يتم تنفيذ الدالة التي تم إدخال تعليقات توضيحية عليها باستخدام
@Before
، وتُنشئSleepDatabase
في الذاكرة باستخدامSleepDatabaseDao
. "In-memory" تعني أن قاعدة البيانات هذه غير محفوظة في نظام الملفات وسيتم حذفها بعد إجراء الاختبارات. - وعند إنشاء قاعدة البيانات المتوفّرة في الذاكرة، يطلب الرمز طريقة أخرى خاصة بالاختبار، وهي
allowMainThreadQueries
. ستظهر لك رسالة خطأ تلقائيًا إذا حاولت تنفيذ طلبات بحث في سلسلة المحادثات الرئيسية. تسمح لك هذه الطريقة بإجراء اختبارات على سلسلة المحادثات الرئيسية، ويجب تنفيذها فقط أثناء الاختبار. - في طريقة اختبار تم إدخال تعليقات توضيحية عليها باستخدام
@Test
، يمكنك إنشاءSleepNight
وإدراجه واسترداده، وتأكيد أنها متماثلة. إذا حدث أي خطأ، استبعد استثناءً. في الاختبار الفعلي، ستتوفر لك طرق@Test
متعددة. - عند الانتهاء من الاختبار، يتم تنفيذ الدالة المزوّدة بتعليقات توضيحية مع
@After
لإغلاق قاعدة البيانات.
- انقر بزر الماوس الأيمن على ملف الاختبار في جزء المشروع واختَر Run 'SleepDatabaseTest'.
- بعد إجراء الاختبارات، تحقق في جزء SleepDatabaseTest من اجتياز جميع الاختبارات.
بما أنّ كل الاختبارات قد تم اجتيازها، أصبحت على دراية بعدة أمور:
- يتم إنشاء قاعدة البيانات بشكل صحيح.
- يمكنك إدراج
SleepNight
في قاعدة البيانات. - يمكنك استعادة
SleepNight
. - يحتوي
SleepNight
على القيمة الصحيحة للجودة.
مشروع "استوديو Android": TrackMySleepqualityRoomAndTesting
عند اختبار قاعدة بيانات، يجب أن تمارس جميع الطرق المحددة في جدول البيانات الرقمي (DAO). ولإكمال الاختبار، أضِف الاختبارات ونفِّذها لممارسة طرق DAO الأخرى.
- حدِّد جداولك كفئات بيانات تحتوي على تعليقات توضيحية باستخدام
@Entity
. ويمكنك تحديد الخصائص التي تم إدخال تعليقات توضيحية عليها باستخدام@ColumnInfo
كأعمدة في الجداول. - حدِّد كائن الوصول إلى البيانات (DAO) كواجهة بها تعليقات توضيحية تتضمن
@Dao
. تربط DAO وظائف Kotlin بطلبات بحث قاعدة البيانات. - استخدِم التعليقات التوضيحية لتحديد الدوال
@Insert
و@Delete
و@Update
. - استخدِم التعليق التوضيحي
@Query
مع سلسلة طلب بحث SQLite كمعلمة لأي طلبات بحث أخرى. - أنشئ فئة ملخصة تحتوي على الدالة
getInstance()
التي تعرض قاعدة بيانات. - استخدِم الاختبارات المقدَّمة من أجل اختبار عمل قاعدة البيانات وDAO على النحو المتوقَّع. ويمكنك استخدام الاختبارات المقدَّمة كنموذج.
دورة Udacity:
مستندات مطوّري برامج Android:
RoomDatabase
Database
(تعليقات توضيحية)- يمكنك استخدام طلبات البحث الأولية مع
Room
Roomdatabase.Builder
- تدريب الاختبار
SQLiteDatabase
صفDao
Room
مكتبة ثابتة
وثائق ومقالات أخرى:
يسرد هذا القسم المهام الدراسية المحتملة للطلاب الذين يعملون من خلال هذا الدرس التطبيقي حول الترميز في إطار دورة تدريبية يُديرها معلِّم. يجب أن ينفِّذ المعلّم ما يلي:
- يمكنك تخصيص واجب منزلي إذا لزم الأمر.
- التواصل مع الطلاب بشأن كيفية إرسال الواجبات المنزلية
- وضع درجات للواجبات المنزلية.
ويمكن للمعلّمين استخدام هذه الاقتراحات بقدر ما يريدون أو بقدر ما يريدون، ويجب عدم التردد في تخصيص أي واجبات منزلية أخرى مناسبة.
إذا كنت تستخدم هذا الدرس التطبيقي بنفسك، يمكنك استخدام هذه الواجبات المنزلية لاختبار معلوماتك.
الإجابة عن هذه الأسئلة
السؤال 1
كيف تشير إلى أنّ صفًا يمثّل كيانًا لتخزينه في قاعدة بيانات Room
؟
- توسيع الصف
DatabaseEntity
. - يمكنك إضافة تعليقات توضيحية إلى الصف
@Entity
. - يمكنك إضافة تعليقات توضيحية إلى الصف
@Database
. - توسيع الصف
RoomEntity
وإضافة تعليق توضيحي للصف باستخدام@Room
.
السؤال 2
DAO (كائن الوصول إلى البيانات) هو واجهة يستخدمها Room
لربط وظائف Kotlin لطلبات بحث قاعدة البيانات.
كيف يتم توضيح أن الواجهة تمثل DAO لقاعدة بيانات Room
؟
- مدِّد الواجهة
RoomDAO
. - مدِّد الواجهة
EntityDao
، ثم نفِّذ الطريقةDaoConnection()
. - إضافة تعليقات توضيحية إلى الواجهة باستخدام
@Dao
. - إضافة تعليقات توضيحية إلى الواجهة باستخدام
@RoomConnection
.
السؤال 3
أي من العبارات التالية صحيحة في قاعدة البيانات Room
؟ يُرجى اختيار جميع الإجابات المناسبة.
- يمكنك تحديد جداول لقاعدة بيانات
Room
كفئات بيانات تتضمن تعليقات توضيحية. - في حال عرض
LiveData
من طلب البحث، سيحتفظRoom
بآخرLiveData
نيابةً عنك إذا تغيّرLiveData
. - يجب أن تتضمن كل قاعدة بيانات
Room
قاعدة DAO واحدة فقط. - لتحديد فئة كقاعدة بيانات
Room
، اجعلها فئة فرعية منRoomDatabase
وأضف تعليقات توضيحية إليها باستخدام@Database
.
السؤال 4
أي من التعليقات التوضيحية التالية يمكنك استخدامه في واجهة @Dao
؟ يُرجى اختيار جميع الإجابات المناسبة.
@Get
@Update
@Insert
@Query
السؤال 5
كيف يمكنك التحقق من أن قاعدة البيانات تعمل؟ يُرجى اختيار كل الإجابات المناسبة.
- كتابة الاختبارات الآلية
- تابع كتابة التطبيق وتشغيله إلى أن يعرض البيانات.
- استبدل المكالمات بالطرق في واجهة DAO من خلال استدعاءات للطرق المعادلة في الفئة
Entity
. - شغِّل الدالة
verifyDatabase()
التي توفِّرها مكتبةRoom
.
ابدأ بالدرس التالي:
وللحصول على روابط إلى دروس تطبيقية أخرى حول الترميز في هذه الدورة التدريبية، يُرجى الاطّلاع على الصفحة المقصودة لتطبيق الدروس التطبيقية حول الترميز Kotlin Fundamentals.