שמירת נתונים במסד נתונים מקומי באמצעות Room   חלק מ-Android Jetpack.

אפליקציות שמטפלות בכמויות לא קטנות של נתונים מובְנים יכולות להפיק תועלת רבה מהשמירה של הנתונים האלה באופן מקומי. התרחיש הנפוץ ביותר הוא שמירת קטעי נתונים רלוונטיים במטמון, כך שבמקרה שהמכשיר לא יכול לגשת לרשת, המשתמש עדיין יוכל לעיין בתוכן הזה במצב אופליין.

ספריית Room לשימור נתונים מספקת שכבת הפשטה מעל SQLite, שמאפשרת גישה חלקה למסד הנתונים תוך ניצול מלוא העוצמה של SQLite. באופן ספציפי, Room מספק את היתרונות הבאים:

  • אימות של שאילתות SQL בזמן הידור.
  • הערות נוחות שמצמצמות את הצורך בקוד סטנדרטי חוזר ונשנה שעלול להכיל שגיאות.
  • נתיבי העברה יעילים יותר של מסדי נתונים.

בגלל השיקולים האלה, מומלץ מאוד להשתמש ב-Room במקום להשתמש ישירות בממשקי ה-API של SQLite.

הגדרה

כדי להשתמש ב-Room באפליקציה, מוסיפים את יחסי התלות הבאים לקובץ build.gradle של האפליקציה.

Kotlin

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

Groovy

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) שמספקים שיטות שבהן האפליקציה יכולה להשתמש כדי להריץ שאילתות, לעדכן, להוסיף ולמחוק נתונים במסד הנתונים.

הכיתה של מסד הנתונים מספקת לאפליקציה מופעים של ה-DAOs שמשויכים למסד הנתונים הזה. בתורו, האפליקציה יכולה להשתמש ב-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);
}

מידע נוסף על DAO מופיע במאמר גישה לנתונים באמצעות DAO של 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();
}

הערה: אם האפליקציה פועלת בתהליך יחיד, צריך לפעול לפי תבנית העיצוב של מודל singleton כשיוצרים אובייקט AppDatabase. כל מכונה של RoomDatabase יקרה למדי, ונדיר שצריך גישה לכמה מכונות בתוך תהליך אחד.

אם האפליקציה פועלת בכמה תהליכים, צריך לכלול את enableMultiInstanceInvalidation() בקריאה ל-builder של מסד הנתונים. כך, כשיש מופע של 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 זמין במקורות המידע הבאים:

דוגמיות

Codelabs

בלוגים