ה-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
. - שימו לב שהערך
interface
SleepDatabaseDao
מסומן בהערה@Dao
. צריך להוסיף את מילת המפתח@Dao
לכל אובייקט DAO.
@Dao
interface SleepDatabaseDao {}
- בתוך גוף הממשק, מוסיפים הערה
@Insert
. מתחת ל-@Insert
, מוסיפים פונקצייתinsert()
שמקבלת מופע של המחלקהEntity
SleepNight
כארגומנט.
זה הכול. Room
ייצור את כל הקוד הדרוש להוספתSleepNight
למסד הנתונים. כשמתקשרים אלinsert()
מקוד Kotlin, Room
מריץ שאילתת SQL כדי להוסיף את הישות למסד הנתונים. (הערה: אפשר לתת לפונקציה כל שם שרוצים).
@Insert
fun insert(night: SleepNight)
- הוספת הערה
@Update
עם פונקציהupdate()
לSleepNight
אחד. הישויות שמתעדכנות הן אלה שיש להן מפתח זהה לזה שמועבר. אפשר לעדכן חלק מהמאפיינים האחרים של הישות או את כולם.
@Update
fun update(night: SleepNight)
אין הערה נוחה לפונקציונליות הנותרת, ולכן צריך להשתמש בהערה @Query
ולספק שאילתות SQLite.
- מוסיפים הערה
@Query
עם פונקציהget()
שמקבלת ארגומנטLong
key
ומחזירה ערךSleepNight
שניתן לאכלוס בערך null. תוצג שגיאה לגבי פרמטר חסר.
@Query
fun get(key: Long): SleepNight?
- השאילתה מסופקת כפרמטר מחרוזת להערה. מוסיפים פרמטר ל-
@Query
. הופכים אותו לString
שהוא שאילתת SQLite.
- בוחרים את כל העמודות מתוך
daily_sleep_quality_table
-
WHERE
nightId
תואם לארגומנט :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
Dao
Room
ספריית התמדה
מסמכים ומאמרים נוספים:
בקטע הזה מפורטות אפשרויות למשימות ביתיות לתלמידים שעובדים על ה-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.