ה-codelab הזה הוא חלק מהקורס Android Kotlin Fundamentals. כדי להפיק את המרב מהקורס הזה, מומלץ לעבוד על ה-codelabs לפי הסדר. כל ה-codelab של הקורס מפורטים בדף הנחיתה של ה-codelab בנושא יסודות Kotlin ל-Android.
מבוא
ברוב האפליקציות יש נתונים שצריך לשמור, גם אחרי שהמשתמש סוגר את האפליקציה. לדוגמה, האפליקציה יכולה לאחסן פלייליסט, מלאי של פריטים במשחק, רשומות של הוצאות והכנסות, קטלוג של קבוצות כוכבים או נתוני שינה לאורך זמן. בדרך כלל משתמשים במסד נתונים כדי לאחסן נתונים קבועים.
Room היא ספריית מסדי נתונים שמהווה חלק מ-Jetpack. Room מטפל בהרבה מהמשימות של הגדרת מסד נתונים וקביעת ההגדרות שלו, ומאפשר לאפליקציה שלכם ליצור אינטראקציה עם מסד הנתונים באמצעות קריאות רגילות לפונקציות. מתחת לפני השטח, Room היא שכבת הפשטה מעל מסד נתונים של SQLite. הטרמינולוגיה של Room ותחביר השאילתות בשאילתות מורכבות יותר מבוססים על מודל SQLite.
בתמונה שלמטה אפשר לראות איך מסד הנתונים Room משתלב בארכיטקטורה הכוללת שמומלצת בקורס הזה.

מה שכדאי לדעת
חשוב שתכירו את:
- איך בונים ממשק משתמש (UI) בסיסי לאפליקציית Android
- שימוש בפעילויות, בקטעים ובתצוגות.
- ניווט בין פרגמנטים ושימוש ב-Safe Args (תוסף Gradle) כדי להעביר נתונים בין פרגמנטים.
- הצגת מודלים, מפעלים של מודלים לתצוגה ו-
LiveDataוהמשתמשים שלו. הנושאים האלה של רכיבי ארכיטקטורה מוסברים ב-codelab קודם בקורס הזה. - הבנה בסיסית של מסדי נתונים של SQL ושפת SQLite. אפשר לקרוא את המדריך המהיר ל-SQLite כדי לקבל סקירה כללית או לרענן את הידע.
מה תלמדו
- איך יוצרים מסד נתונים של
Roomואיך מקיימים איתו אינטראקציה כדי לשמור נתונים. - איך ליצור מחלקת נתונים שמגדירה טבלה במסד הנתונים.
- איך משתמשים באובייקט לגישה לנתונים (DAO) כדי למפות פונקציות של Kotlin לשאילתות SQL.
- איך בודקים אם מסד הנתונים פועל.
הפעולות שתבצעו:
- יצירת מסד נתונים של
Roomעם ממשק לנתוני שינה ליליים. - בודקים את מסד הנתונים באמצעות הבדיקות שסופקו.
ב-codelab הזה, תבנו את החלק של מסד הנתונים באפליקציה שעוקבת אחרי איכות השינה. האפליקציה משתמשת במסד נתונים כדי לאחסן את נתוני השינה לאורך זמן.
לאפליקציה יש שני מסכים שמיוצגים על ידי קטעים, כמו שמוצג באיור שלמטה.
במסך הראשון, שמוצג בצד ימין, יש לחצנים להתחלת המעקב ולהפסקתו. במסך מוצגים כל נתוני השינה של המשתמש. הלחצן ניקוי מוחק באופן סופי את כל הנתונים שהאפליקציה אספה על המשתמש.
במסך השני, שמוצג בצד שמאל, בוחרים את דירוג איכות השינה. באפליקציה, הדירוג מיוצג בצורה מספרית. למטרות פיתוח, האפליקציה מציגה גם את סמלי הפנים וגם את הערכים המספריים שלהם.
מסלול המשתמש הוא כדלקמן:
- המשתמש פותח את האפליקציה ומוצג לו מסך מעקב השינה.
- המשתמש מקיש על הלחצן התחלה. השדה הזה מתעד את שעת ההתחלה ומציג אותה. הלחצן התחלה מושבת, והלחצן עצירה מופעל.
- המשתמש מקיש על הלחצן הפסקה. השעה שבה תסיימו לישון תתועד ותיפתח לכם האפשרות לדרג את איכות השינה.
- המשתמש בוחר בסמל של איכות השינה. המסך נסגר, ובמסך המעקב מוצגים שעת סיום השינה ואיכות השינה. הלחצן עצירה מושבת והלחצן התחלה מופעל. האפליקציה מוכנה לעוד לילה.
- הלחצן ניקוי מופעל בכל פעם שיש נתונים במסד הנתונים. כשמשתמש מקיש על הלחצן ניקוי, כל הנתונים שלו נמחקים בלי אפשרות לשחזור – לא מוצגת הודעה עם השאלה 'האם אתה בטוח?'.
האפליקציה הזו משתמשת בארכיטקטורה פשוטה, כפי שמוצג בהמשך בהקשר של הארכיטקטורה המלאה. האפליקציה משתמשת רק ברכיבים הבאים:
- בקר ממשק משתמש
- הצגת הדגם ו-
LiveData - מסד נתונים של Room
שלב 1: הורדה והפעלה של אפליקציית המתחילים
- מורידים את האפליקציה TrackMySleepQuality-Starter מ-GitHub.
- מבצעים Build ומריצים את האפליקציה. ממשק המשתמש של קטע
SleepTrackerFragmentמוצג באפליקציה, אבל לא מוצגים נתונים. הכפתורים לא מגיבים להקשה.
שלב 2: בודקים את אפליקציית המתחילים
- בודקים את קובצי Gradle:
- קובץ Gradle של הפרויקט
בקובץbuild.gradleברמת הפרויקט, שימו לב למשתנים שמציינים את גרסאות הספרייה. הגרסאות שבהן נעשה שימוש באפליקציית המתחילים פועלות היטב יחד, ופועלות היטב עם האפליקציה הזו. עד שתסיימו את ה-codelab הזה, יכול להיות ש-Android Studio יציע לכם לעדכן חלק מהגרסאות. אתם יכולים לבחור אם לעדכן או להישאר עם הגרסאות שמופיעות באפליקציה. אם נתקלתם בשגיאות קומפילציה "מוזרות", נסו להשתמש בשילוב של גרסאות הספריות שבהן נעשה שימוש באפליקציית הפתרון הסופי. - קובץ Gradle של המודול. שימו לב לרכיבים התלויים שסופקו לכל הספריות של Android Jetpack, כולל
Room, ולרכיבים התלויים של קורוטינות.
- כדאי לעיין בחבילות ובממשק המשתמש. האפליקציה בנויה לפי פונקציונליות. החבילה מכילה קבצים של מצייני מיקום שבהם תוסיפו קוד במהלך סדרת ה-codelab הזו.
- החבילה
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הוא המפתח הראשי, מוסיפים את ההערה@PrimaryKeyלמאפייןnightId. מגדירים את הפרמטר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. מגדירים את המיפויים האלה ב-DAO באמצעות הערות, ו-Room יוצר את הקוד הנדרש.
אפשר לחשוב על DAO כהגדרה של ממשק מותאם אישית לגישה למסד הנתונים.
לפעולות נפוצות במסד נתונים, ספריית Room מספקת הערות נוחות, כמו @Insert, @Delete ו-@Update. לכל שאר המקרים, יש את ההערה @Query. אפשר לכתוב כל שאילתה שנתמכת על ידי SQLite.
כבונוס נוסף, בזמן שאתם יוצרים את השאילתות ב-Android Studio, מהדר בודק את שאילתות ה-SQL שלכם כדי לוודא שאין בהן שגיאות תחביר.
כדי להשתמש במסד הנתונים של מעקב השינה, צריך:
- מוסיפים לילות חדשים.
- עדכון של לילה קיים כדי לעדכן את שעת הסיום ואת דירוג האיכות.
- קבלת לילה ספציפי על סמך המפתח שלו.
- Get all nights (קבלת כל הלילות), כדי שתוכלו להציג אותם.
- קבלת הנתונים מהלילה האחרון.
- מחיקה של כל הרשומות במסד הנתונים.
שלב 1: יצירת SleepDatabase DAO
- בחבילה
database, פותחים אתSleepDatabaseDao.kt. - שימו לב שהערך
interfaceSleepDatabaseDaoמסומן בהערה@Dao. צריך להוסיף את מילת המפתח@Daoלכל אובייקט DAO.
@Dao
interface SleepDatabaseDao {}- בתוך גוף הממשק, מוסיפים הערה
@Insert. מתחת ל-@Insert, מוסיפים פונקצייתinsert()שמקבלת מופע של המחלקהEntitySleepNightכארגומנט.
זה הכול. Roomייצור את כל הקוד הדרוש להוספתSleepNightלמסד הנתונים. כשמתקשרים אלinsert()מקוד Kotlin, Roomמריץ שאילתת SQL כדי להוסיף את הישות למסד הנתונים. (הערה: אפשר לתת לפונקציה כל שם שרוצים).
@Insert
fun insert(night: SleepNight)- הוספת הערה
@Updateעם פונקציהupdate()לSleepNightאחד. הישויות שמתעדכנות הן אלה שיש להן מפתח זהה לזה שמועבר. אפשר לעדכן חלק מהמאפיינים האחרים של הישות או את כולם.
@Update
fun update(night: SleepNight)אין הערה נוחה לפונקציונליות הנותרת, ולכן צריך להשתמש בהערה @Query ולספק שאילתות SQLite.
- מוסיפים הערה
@Queryעם פונקציהget()שמקבלת ארגומנטLongkeyומחזירה ערךSleepNightשניתן לאכלוס בערך null. תוצג שגיאה לגבי פרמטר חסר.
@Query
fun get(key: Long): SleepNight?- השאילתה מסופקת כפרמטר מחרוזת להערה. מוסיפים פרמטר ל-
@Query. הופכים אותו לStringשהוא שאילתת SQLite.
- בוחרים את כל העמודות מתוך
daily_sleep_quality_table -
WHEREnightIdתואם לארגומנט :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()לערך שניתן להגדרה כ-null, כדי שהפונקציה תוכל לטפל במקרה שבו הטבלה ריקה. (הטבלה ריקה בהתחלה, ואחרי שהנתונים נמחקים).
כדי לקבל את הערך 'הערב' ממסד הנתונים, צריך לכתוב שאילתת SQLite שמחזירה את הרכיב הראשון ברשימת התוצאות שממוינות לפי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כ-singleton. - משתמשים בכלי ליצירת מסד נתונים של
Roomכדי ליצור את מסד הנתונים רק אם הוא לא קיים. אחרת, מחזירים את מסד הנתונים הקיים.
שלב 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. יכולים להיות לכם כמה ארגונים אוטונומיים מבוזרים.
abstract val sleepDatabaseDao: SleepDatabaseDao- מתחת לזה, מגדירים אובייקט
companion. אובייקט ה-companion מאפשר ללקוחות לגשת לשיטות ליצירה או לקבלת מסד הנתונים בלי ליצור מופע של המחלקה. מכיוון שהמטרה היחידה של המחלקה הזו היא לספק מסד נתונים, אין סיבה ליצור ממנה מופע.
companion object {}- בתוך אובייקט
companion, מגדירים משתנה פרטי שניתן להקצאת ערך Null 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. מתעלמים משגיאת אי ההתאמה של סוג ההחזרה, כי אחרי שמסיימים את הפעולה לא יוחזר ערך null.
return instance- מעל ההצהרה
return, מוסיפים הצהרהifכדי לבדוק אםinstanceהוא null, כלומר, אם עדיין אין מסד נתונים.
if (instance == null) {}- אם הערך של
instanceהואnull, צריך להשתמש בכלי ליצירת מסדי נתונים כדי לקבל מסד נתונים. בגוף ההצהרהif, מפעילים אתRoom.databaseBuilderומספקים את ההקשר שהועבר, את מחלקת מסד הנתונים ואת השם של מסד הנתונים,sleep_history_database. כדי להסיר את השגיאה, צריך להוסיף אסטרטגיית העברה וbuild()בשלבים הבאים.
instance = Room.databaseBuilder(
context.applicationContext,
SleepDatabase::class.java,
"sleep_history_database")- מוסיפים לכלי הבנייה את אסטרטגיית ההעברה הנדרשת. משתמשים ב-
.fallbackToDestructiveMigration().
בדרך כלל, צריך לספק אובייקט העברה עם אסטרטגיית העברה למקרה של שינוי בסכימה. אובייקט העברה הוא אובייקט שמגדיר איך לוקחים את כל השורות עם הסכימה הישנה וממירים אותן לשורות בסכימה החדשה, כך שלא יאבדו נתונים. העברה היא מעבר להיקף של ה-Codelab הזה. פתרון פשוט הוא להרוס את מסד הנתונים ולבנות אותו מחדש, מה שאומר שהנתונים יאבדו.
.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, ולכן צריך להריץ את הבדיקות במכשיר פיזי או וירטואלי. כמובן שאפשר גם ליצור ולהריץ בדיקות יחידה (unit testing) טהורות שלא כוללות את מסגרת Android.
- ב-Android Studio, בתיקייה androidTest, פותחים את הקובץ SleepDatabaseTest.
- כדי לבטל את ההערה של הקוד, בוחרים את כל הקוד שהוספה לו הערה ולוחצים על מקש הקיצור
Cmd+/אוControl+/. - מעיינים בקובץ.
הנה סקירה מהירה של קוד הבדיקה, כי זה עוד קטע קוד שאפשר לעשות בו שימוש חוזר:
-
SleepDabaseTestהיא כיתת ניסוי. - ההערה
@RunWithמזהה את כלי ההרצה של הבדיקות, שהוא התוכנית שמגדירה ומבצעת את הבדיקות. - במהלך ההגדרה, הפונקציה שמסומנת ב-
@Beforeמופעלת, והיא יוצרתSleepDatabaseבזיכרון עםSleepDatabaseDao. 'בזיכרון' פירושו שמסד הנתונים הזה לא נשמר במערכת הקבצים ויימחק אחרי הרצת הבדיקות. - בנוסף, כשיוצרים את מסד הנתונים בזיכרון, הקוד קורא לשיטה ספציפית אחרת לבדיקה,
allowMainThreadQueries. כברירת מחדל, אם מנסים להריץ שאילתות בשרשור הראשי, מוצגת שגיאה. השיטה הזו מאפשרת להריץ בדיקות בשרשור הראשי, ומומלץ לעשות זאת רק במהלך הבדיקות. - בשיטת בדיקה עם ההערה
@Test, יוצרים, מוסיפים ומאחזריםSleepNightומוודאים שהם זהים. אם משהו משתבש, צריך להפעיל חריגה. בבדיקה אמיתית, היו לכם כמה שיטות@Test. - כשהבדיקה מסתיימת, הפונקציה שמסומנת ב-
@Afterמופעלת כדי לסגור את מסד הנתונים.
- לוחצים לחיצה ימנית על קובץ הבדיקה בחלונית Project ובוחרים באפשרות Run 'SleepDatabaseTest'.
- אחרי הרצת הבדיקות, מוודאים בחלונית SleepDatabaseTest שכל הבדיקות עברו.

מכיוון שכל הבדיקות עברו בהצלחה, אתם יודעים עכשיו כמה דברים:
- מסד הנתונים נוצר בצורה תקינה.
- אפשר להוסיף
SleepNightלמסד הנתונים. - אפשר לקבל בחזרה את
SleepNight. - במאפיין
SleepNightמופיע הערך הנכון של האיכות.
פרויקט Android Studio: TrackMySleepQualityRoomAndTesting
כשבודקים מסד נתונים, צריך להפעיל את כל השיטות שמוגדרות ב-DAO. כדי להשלים את הבדיקה, מוסיפים ומריצים בדיקות כדי להפעיל את שאר השיטות של DAO.
- מגדירים את הטבלאות כסוגי נתונים שמסומנים בהערה
@Entity. הגדרת מאפיינים עם ההערה@ColumnInfoכעמודות בטבלאות. - מגדירים אובייקט גישה לנתונים (DAO) כממשק עם ההערה
@Dao. ה-DAO ממפה פונקציות של Kotlin לשאילתות במסד הנתונים. - משתמשים בהערות כדי להגדיר את הפונקציות
@Insert,@Deleteו-@Update. - משתמשים בהערה
@Queryעם מחרוזת שאילתה של SQLite כפרמטר לכל שאילתה אחרת. - יוצרים מחלקה מופשטת עם פונקציה
getInstance()שמחזירה מסד נתונים. - משתמשים בבדיקות עם מכשור כדי לוודא שמסד הנתונים ו-DAO פועלים כמצופה. אפשר להשתמש בבדיקות שסופקו כתבנית.
קורס ב-Udacity:
מסמכי תיעוד למפתחי Android:
RoomDatabase-
Database(הערות) - אפשר להשתמש בשאילתות גולמיות עם
Room Roomdatabase.Builder- הדרכה בנושא בדיקות
- כיתה
SQLiteDatabase DaoRoomספריית התמדה
מסמכים ומאמרים נוספים:
בקטע הזה מפורטות אפשרויות למשימות ביתיות לתלמידים שעובדים על ה-Codelab הזה כחלק מקורס בהנחיית מדריך. המורה צריך:
- אם צריך, מקצים שיעורי בית.
- להסביר לתלמידים איך להגיש מטלות.
- בודקים את שיעורי הבית.
אנשי ההוראה יכולים להשתמש בהצעות האלה כמה שרוצים, ומומלץ להם להקצות כל שיעורי בית אחרים שהם חושבים שמתאימים.
אם אתם עובדים על ה-codelab הזה לבד, אתם יכולים להשתמש במשימות האלה כדי לבדוק את הידע שלכם.
עונים על השאלות הבאות
שאלה 1
איך מציינים שמחלקה מייצגת ישות לאחסון במסד נתונים Room?
- מרחיבים את הכיתה
DatabaseEntity. - מוסיפים הערות לכיתה עם
@Entity. - מוסיפים הערות לכיתה עם
@Database. - הארכת השיעור ב-
RoomEntityוהוספת הערות לשיעור ב-@Room.
שאלה 2
ה-DAO (אובייקט גישה לנתונים) הוא ממשק ש-Room משתמש בו כדי למפות פונקציות של Kotlin לשאילתות במסד הנתונים.
איך מציינים שממשק מייצג DAO עבור מסד נתונים של Room?
- הגדרת הממשק כך שיתרחב
RoomDAO. - מגדירים את הממשק כך שירחיב את
EntityDao, ואז מטמיעים את ה-methodDaoConnection(). - הוספת הערות לממשק באמצעות
@Dao. - הוספת הערות לממשק באמצעות
@RoomConnection.
שאלה 3
אילו מההצהרות הבאות נכונות לגבי מסד הנתונים Room? צריך לבחור בכל האפשרויות הרלוונטיות.
- אפשר להגדיר טבלאות למסד נתונים של
Roomכסוגי נתונים עם הערות. - אם מחזירים את
LiveDataמשאילתה,Roomידאג לעדכן אתLiveDataאם הוא ישתנה.LiveData - לכל מסד נתונים
Roomצריך להיות DAO אחד בלבד. - כדי להגדיר מחלקה כ
Roomמסד נתונים, צריך להגדיר אותה כמחלקת משנה שלRoomDatabaseולהוסיף לה את ההערה@Database.
שאלה 4
אילו מההערות הבאות אפשר להוסיף בממשק של @Dao? צריך לבחור בכל האפשרויות הרלוונטיות.
@Get@Update@Insert@Query
שאלה 5
איך אפשר לוודא שהמסד נתונים פועל? יש לבחור בכל האפשרויות הרלוונטיות.
- כתיבת בדיקות עם מכשור.
- ממשיכים לכתוב ולהריץ את האפליקציה עד שהנתונים מוצגים.
- מחליפים את הקריאות ל-methods בממשק DAO בקריאות ל-methods מקבילים במחלקה
Entity. - מריצים את הפונקציה
verifyDatabase()שסופקה על ידי הספרייהRoom.
עוברים לשיעור הבא:
קישורים ל-codelabs אחרים בקורס הזה מופיעים בדף הנחיתה של ה-codelabs בנושא יסודות Android Kotlin.