حفظ البيانات في قاعدة بيانات محلية باستخدام Room   أحد مكونات Android Jetpack

تجربة Kotlin Multiplatform
تتيح Kotlin Multiplatform مشاركة طبقة قاعدة البيانات مع منصات أخرى. تعرَّف على كيفية إعداد Room Database واستخدامه في KMP

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

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

  • التحقّق من صحة طلبات البحث بلغة SQL في وقت الترجمة البرمجية
  • تعليقات توضيحية تسهّل الاستخدام وتقلّل من تكرار النصوص النموذجية المعرَّضة للأخطاء
  • مسارات مبسطة لنقل قواعد البيانات

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

ضبط إعدادات الميزة

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

Kotlin

dependencies {
    val room_version = "2.7.2"

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

Groovy

dependencies {
    def room_version = "2.7.2"

    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) التي توفّر طرقًا يمكن لتطبيقك استخدامها للاستعلام عن البيانات وتعديلها وإدراجها وحذفها في قاعدة البيانات

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

الشكل 1. مخطّط لبنية مكتبة Room

مثال على التنفيذ

يعرض هذا القسم مثالاً على تنفيذ قاعدة بيانات Room تتضمّن كيان بيانات واحدًا و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;
}

لمزيد من المعلومات حول عناصر البيانات في Room، يمكنك الاطّلاع على تحديد البيانات باستخدام عناصر Room.

كائن الوصول إلى البيانات (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);
}

لمزيد من المعلومات عن كائنات الوصول إلى البيانات، يمكنك الاطّلاع على الوصول إلى البيانات باستخدام كائنات الوصول إلى البيانات في Room.

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

يحدد الرمز التالي فئة 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();

مراجع إضافية

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

نماذج

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

المدوّنات