حفظ البيانات في قاعدة بيانات محلية باستخدام Room جزء من Android Jetpack.
يمكن للتطبيقات التي تتعامل مع كميات كبيرة من البيانات المنظَّمة الاستفادة بشكل كبير من تخزين هذه البيانات على الجهاز. وأكثر حالات الاستخدام شيوعًا هي تخزين مقتطفات البيانات ذات الصلة مؤقتًا لكي يظل بإمكان المستخدم تصفّح هذا المحتوى بلا إنترنت عندما يتعذّر على الجهاز الوصول إلى الشبكة.
توفّر مكتبة Room للحفاظ على البيانات طبقة تجريدية فوق SQLite للسماح بالوصول إلى قاعدة البيانات بسلاسة مع الاستفادة من الإمكانات الكاملة لـ SQLite. على وجه الخصوص، يقدّم Room المزايا التالية:
- التحقّق من طلبات لغة الاستعلامات البنيوية (SQL) في وقت الترجمة
- التعليقات التوضيحية الملائمة التي تقلّل من النصوص النموذجية المتكرّرة والمعرضة للأخطاء
- مسارات نقل قاعدة البيانات المبسّطة
وبناءً على هذه الاعتبارات، ننصحك بشدة باستخدام Room بدلاً من استخدام واجهات برمجة تطبيقات SQLite مباشرةً.
ضبط إعدادات الجهاز
لاستخدام Room في تطبيقك، أضِف الملحقات التالية إلى ملف
build.gradle
في تطبيقك.
dependencies { val room_version = "2.6.1" implementation("androidx.room:room-runtime:$room_version") // If this project uses any Kotlin source, use Kotlin Symbol Processing (KSP) // See Add the KSP plugin to your project ksp("androidx.room:room-compiler:$room_version") // If this project only uses Java source, use the Java annotationProcessor // No additional plugins are necessary annotationProcessor("androidx.room:room-compiler:$room_version") // optional - Kotlin Extensions and Coroutines support for Room implementation("androidx.room:room-ktx:$room_version") // optional - RxJava2 support for Room implementation("androidx.room:room-rxjava2:$room_version") // optional - RxJava3 support for Room implementation("androidx.room:room-rxjava3:$room_version") // optional - Guava support for Room, including Optional and ListenableFuture implementation("androidx.room:room-guava:$room_version") // optional - Test helpers testImplementation("androidx.room:room-testing:$room_version") // optional - Paging 3 Integration implementation("androidx.room:room-paging:$room_version") }
dependencies { def room_version = "2.6.1" implementation "androidx.room:room-runtime:$room_version" // If this project uses any Kotlin source, use Kotlin Symbol Processing (KSP) // See KSP Quickstart to add KSP to your build ksp "androidx.room:room-compiler:$room_version" // If this project only uses Java source, use the Java annotationProcessor // No additional plugins are necessary annotationProcessor "androidx.room:room-compiler:$room_version" // optional - RxJava2 support for Room implementation "androidx.room:room-rxjava2:$room_version" // optional - RxJava3 support for Room implementation "androidx.room:room-rxjava3:$room_version" // optional - Guava support for Room, including Optional and ListenableFuture implementation "androidx.room:room-guava:$room_version" // optional - Test helpers testImplementation "androidx.room:room-testing:$room_version" // optional - Paging 3 Integration implementation "androidx.room:room-paging:$room_version" }
المكونات الأساسية
هناك ثلاثة مكوّنات رئيسية في Room:
- فئة قاعدة البيانات التي تحتوي على قاعدة البيانات وتعمل بمثابة نقطة الوصول الرئيسية للاتصال الأساسي ببيانات تطبيقك الثابتة
- كيانات البيانات التي تمثّل الجداول في قاعدة بيانات تطبيقك
- عناصر الوصول إلى البيانات (DAO) التي توفّر methods يمكن لتطبيقك استخدامها لطلب طلبات بحث عن data في قاعدة البيانات وتعديلها وإدراجها وحذفها
توفّر فئة قاعدة البيانات لتطبيقك مثيلات لـ DAO المرتبطة بقاعدة البيانات هذه. في المقابل، يمكن للتطبيق استخدام واجهة DAO لاسترداد البيانات من قاعدة بيانات كمثيلات لكائنات عناصر البيانات المرتبطة. يمكن للتطبيق أيضًا استخدام كيانات البيانات المحدّدة لتعديل الصفوف من الجداول المقابلة، أو لإنشاء صفوف جديدة لإدراجها. يوضّح الشكل 1 العلاقة بين المكوّنات المختلفة لـ Room.
مثال على التنفيذ
يقدّم هذا القسم مثالاً على تنفيذ قاعدة بيانات Room باستخدام كينان data واحد وDAO واحد.
عنصر البيانات
تحدِّد التعليمة البرمجية التالية عنصر بيانات User
. يمثّل كل مثيل من User
صفًا في جدول user
في قاعدة بيانات التطبيق.
@Entity data class User( @PrimaryKey val uid: Int, @ColumnInfo(name = "first_name") val firstName: String?, @ColumnInfo(name = "last_name") val lastName: String? )
@Entity public class User { @PrimaryKey public int uid; @ColumnInfo(name = "first_name") public String firstName; @ColumnInfo(name = "last_name") public String lastName; }
لمزيد من المعلومات عن عناصر البيانات في Room، اطّلِع على مقالة تحديد البيانات باستخدام عناصر Room.
كائن الوصول إلى البيانات (DAO)
تحدِّد التعليمة البرمجية التالية DAO باسم UserDao
. يوفّر UserDao
methods التي تستخدمها بقية أجزاء التطبيق للتفاعل مع البيانات في جدول user
.
@Dao interface UserDao { @Query("SELECT * FROM user") fun getAll(): List<User> @Query("SELECT * FROM user WHERE uid IN (:userIds)") fun loadAllByIds(userIds: IntArray): List<User> @Query("SELECT * FROM user WHERE first_name LIKE :first AND " + "last_name LIKE :last LIMIT 1") fun findByName(first: String, last: String): User @Insert fun insertAll(vararg users: User) @Delete fun delete(user: User) }
@Dao public interface UserDao { @Query("SELECT * FROM user") List<User> getAll(); @Query("SELECT * FROM user WHERE uid IN (:userIds)") List<User> loadAllByIds(int[] userIds); @Query("SELECT * FROM user WHERE first_name LIKE :first AND " + "last_name LIKE :last LIMIT 1") User findByName(String first, String last); @Insert void insertAll(User... users); @Delete void delete(User user); }
لمزيد من المعلومات عن DAO، اطّلِع على مقالة الوصول إلى البيانات باستخدام DAO Room.
قاعدة البيانات
تحدِّد التعليمة البرمجية التالية فئة AppDatabase
لتخزين قاعدة البيانات.
تحدِّد AppDatabase
إعدادات قاعدة البيانات وتُستخدَم كنقطة
وصول التطبيق الرئيسية إلى البيانات الثابتة. يجب أن تستوفي فئة قاعدة البيانات الشروط التالية:
- يجب أن يكون الصفّ مُعلَقًا بتعليق توضيحي
@Database
يحتوي على مصفوفةentities
تسرد جميع كيانات البيانات المرتبطة بقاعدة البيانات. - يجب أن تكون الفئة فئة مجردة تمديدًا لمحاولة
RoomDatabase
. - بالنسبة إلى كل فئة DAO مرتبطة بقاعدة البيانات، يجب أن تحدِّد فئة قاعدة البيانات طريقة مجردة لا تحتوي على أيّ وسيطات وتُعيد مثيلًا لفئة DAO.
@Database(entities = [User::class], version = 1) abstract class AppDatabase : RoomDatabase() { abstract fun userDao(): UserDao }
@Database(entities = {User.class}, version = 1) public abstract class AppDatabase extends RoomDatabase { public abstract UserDao userDao(); }
ملاحظة: إذا كان تطبيقك يعمل في عملية واحدة، عليك اتّباع
نمط التصميم للعنصر الفردي عند إنشاء مثيل لعنصر AppDatabase
. إنّ كلّ نسخة من RoomDatabase
باهظة التكلفة إلى حدٍّ ما، وقلّما تحتاج
إلى الوصول إلى نُسخ متعدّدة ضمن عملية واحدة.
إذا كان تطبيقك يعمل في عمليات متعددة، أدرِج enableMultiInstanceInvalidation()
في استدعاء enableMultiInstanceInvalidation()
لإنشاء قاعدة البيانات. بهذه الطريقة، عندما يكون لديك مثيل من AppDatabase
في كل عملية، يمكنك إلغاء صلاحية ملف قاعدة البيانات المشترَكة في عملية واحدة،
ويتم نشر هذا الإلغاء تلقائيًا إلى نُسخ AppDatabase
في العمليات الأخرى.
الاستخدام
بعد تحديد عنصر البيانات وDAO وعنصر قاعدة البيانات، يمكنك استخدام الرمز البرمجي التالي لإنشاء مثيل لقاعدة البيانات:
val db = Room.databaseBuilder( applicationContext, AppDatabase::class.java, "database-name" ).build()
AppDatabase db = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "database-name").build();
يمكنك بعد ذلك استخدام الطرق المجردة من AppDatabase
للحصول على مثيل
لـ DAO. بدورك، يمكنك استخدام الطرق من مثيل DAO للتفاعل
مع قاعدة البيانات:
val userDao = db.userDao() val users: List<User> = userDao.getAll()
UserDao userDao = db.userDao(); List<User> users = userDao.getAll();
مصادر إضافية
لمزيد من المعلومات عن Room، يُرجى الاطّلاع على المراجع الإضافية التالية: