يمكنك حفظ البيانات في قاعدة بيانات محلية باستخدام Room جزء من Android Jetpack.

يمكن للتطبيقات التي تتعامل مع كميات بسيطة من البيانات المنظَّمة أن تستفيد بشكل كبير من الاحتفاظ بالبيانات على المستوى المحلي. تتمثل حالة الاستخدام الأكثر شيوعًا في تخزين أجزاء البيانات ذات الصلة بحيث لا يتمكن الجهاز من الوصول إلى الشبكة، ويظل المستخدم يتصفح هذا المحتوى أثناء عدم اتصاله بالإنترنت.

توفر مكتبة استمرارية الغرفة طبقة تجريد عبر SQLite للسماح بالوصول بطلاقة إلى قاعدة البيانات مع الاستفادة من إمكانيات SQLite الكاملة. على وجه الخصوص، تقدّم Room المزايا التالية:

  • التحقق في وقت التجميع من طلبات لغة الاستعلامات البنيوية (SQL)
  • التعليقات التوضيحية الملائمة التي تقلل من الرموز النموذجية المتكررة والتي تكون عرضة للأخطاء.
  • مسارات نقل بيانات قواعد البيانات مُبسّطة

بسبب هذه الاعتبارات، ننصحك بشدة باستخدام الغرفة بدلاً من استخدام واجهات برمجة تطبيقات SQLite مباشرةً.

ضبط إعدادات

لاستخدام Room في تطبيقك، أضِف العناصر الاعتمادية التالية إلى ملف build.gradle في تطبيقك:

رائع

dependencies {
    def room_version = "2.6.1"

    implementation "androidx.room:room-runtime:$room_version"
    annotationProcessor "androidx.room:room-compiler:$room_version"

    // To use Kotlin annotation processing tool (kapt)
    kapt "androidx.room:room-compiler:$room_version"
    // To use Kotlin Symbol Processing (KSP)
    ksp "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"
}

Kotlin

dependencies {
    val room_version = "2.6.1"

    implementation("androidx.room:room-runtime:$room_version")
    annotationProcessor("androidx.room:room-compiler:$room_version")

    // To use Kotlin annotation processing tool (kapt)
    kapt("androidx.room:room-compiler:$room_version")
    // To use Kotlin Symbol Processing (KSP)
    ksp("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")
}

المكونات الأساسية

تتضمّن الغرفة ثلاثة مكونات رئيسية:

  • فئة قاعدة البيانات التي تحتفظ بقاعدة البيانات وتعمل كنقطة الوصول الرئيسية للاتصال الأساسي ببيانات تطبيقك المحفوظة.
  • كيانات البيانات التي تمثل الجداول في قاعدة بيانات تطبيقك.
  • كائنات الوصول إلى البيانات (DAOs) التي توفّر طرقًا يمكن لتطبيقك استخدامها للاستعلام عن البيانات في قاعدة البيانات وتعديلها وإدراجها وحذفها في قاعدة البيانات.

تزود فئة قاعدة البيانات تطبيقك بمثيلات من DAO المرتبطة بقاعدة البيانات تلك. وفي المقابل، يمكن للتطبيق استخدام وحدات DAO لاسترداد البيانات من قاعدة البيانات كمثيلات لكائنات كيان البيانات المرتبطة. يمكن للتطبيق أيضًا استخدام كيانات البيانات المحددة لتحديث الصفوف من الجداول المقابلة، أو إنشاء صفوف جديدة لإدراجها. يوضح الشكل 1 العلاقة بين المكونات المختلفة للغرفة.

الشكل 1. رسم توضيحي لبنية مكتبة الغرف

نموذج عملية التنفيذ

يقدم هذا القسم مثالاً على تنفيذ قاعدة بيانات غرفة باستخدام كيان بيانات واحد ونظام DAO واحد.

كيان البيانات

يحدّد الرمز التالي كيان بيانات User. يمثل كل مثيل User صفًا في جدول user في قاعدة بيانات التطبيق.

Kotlin

@Entity
data class User(
    @PrimaryKey val uid: Int,
    @ColumnInfo(name = "first_name") val firstName: String?,
    @ColumnInfo(name = "last_name") val lastName: String?
)

Java

@Entity
public class User {
    @PrimaryKey
    public int uid;

    @ColumnInfo(name = "first_name")
    public String firstName;

    @ColumnInfo(name = "last_name")
    public String lastName;
}

لمزيد من المعلومات عن كيانات البيانات في الغرفة، يُرجى الاطّلاع على تعريف البيانات باستخدام كيانات الغرفة.

كائن الوصول إلى البيانات (DAO)

يحدّد الرمز التالي قائمة DAO تسمى UserDao. UserDao توفر الطرق التي يستخدمها باقي التطبيق للتفاعل مع البيانات في جدول user.

Kotlin

@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)
}

Java

@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);
}

لمعرفة المزيد من المعلومات عن DAOs، يُرجى الاطّلاع على الوصول إلى البيانات باستخدام DAOs للغرفة.

قاعدة البيانات

يحدّد الرمز التالي فئة AppDatabase للاحتفاظ بقاعدة البيانات. وتحدّد الخاصية AppDatabase إعدادات قاعدة البيانات وتعمل كنقطة وصول رئيسية للتطبيق إلى البيانات المحفوظة. يجب أن تستوفي فئة قاعدة البيانات الشروط التالية:

  • يجب إضافة تعليق توضيحي إلى الصف يتضمّن تعليق توضيحي من @Database يتضمّن مصفوفة entities تسرد جميع كيانات البيانات المرتبطة بقاعدة البيانات.
  • يجب أن يكون الصف عبارة عن فئة مجردة تمتد إلى RoomDatabase.
  • لكل فئة DAO مرتبطة بقاعدة البيانات، يجب أن تحدد فئة قاعدة البيانات طريقة مجردة لا تحتوي على وسيطات وترجع مثيلاً من فئة DAO.

Kotlin

@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao
}

Java

@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
    public abstract UserDao userDao();
}

ملاحظة: إذا كان تطبيقك يتم تشغيله في عملية واحدة، عليك اتّباع نمط تصميم نمط "سينغلتون" عند إنشاء مثيل AppDatabase. كل نسخة RoomDatabase باهظة الثمن، ونادرًا ما تحتاج إلى الوصول إلى عدة نُسخ ضمن عملية واحدة.

إذا كان تطبيقك يعمل في عمليات متعدّدة، يمكنك تضمين enableMultiInstanceInvalidation() في استدعاء أداة إنشاء قاعدة البيانات. بهذه الطريقة، عندما يكون لديك مثيل AppDatabase في كل عملية، يمكنك إلغاء صلاحية ملف قاعدة البيانات المشتركة في عملية واحدة، وسيتم نشر هذا الإبطال تلقائيًا في مثيلات AppDatabase في العمليات الأخرى.

الاستخدام

بعد تحديد كيان البيانات وDAO وكائن قاعدة البيانات، يمكنك استخدام التعليمة البرمجية التالية لإنشاء مثيل لقاعدة البيانات:

Kotlin

val db = Room.databaseBuilder(
            applicationContext,
            AppDatabase::class.java, "database-name"
        ).build()

Java

AppDatabase db = Room.databaseBuilder(getApplicationContext(),
        AppDatabase.class, "database-name").build();

يمكنك بعد ذلك استخدام الطرق التجريدية من AppDatabase للحصول على مثيل من DAO. في المقابل، يمكنك استخدام الطرق من مثيل DAO للتفاعل مع قاعدة البيانات:

Kotlin

val userDao = db.userDao()
val users: List<User> = userDao.getAll()

Java

UserDao userDao = db.userDao();
List<User> users = userDao.getAll();

مراجع إضافية

لمعرفة المزيد من المعلومات عن الغرفة، يُرجى الاطّلاع على المراجع الإضافية التالية:

عيّنات

الدروس التطبيقية حول الترميز

المدوّنات