Codelab นี้เป็นส่วนหนึ่งของหลักสูตรหลักพื้นฐานของ Android Kotlin คุณจะได้รับประโยชน์สูงสุดจากหลักสูตรนี้หากทำตาม Codelab ตามลำดับ Codelab ของหลักสูตรทั้งหมดแสดงอยู่ในหน้า Landing Page ของ Codelab หลักพื้นฐานของ Android Kotlin
บทนำ
แอปส่วนใหญ่มีข้อมูลที่ต้องเก็บไว้แม้ว่าผู้ใช้จะปิดแอปแล้วก็ตาม เช่น แอปอาจจัดเก็บเพลย์ลิสต์ รายการไอเทมในเกม บันทึกค่าใช้จ่ายและรายได้ แคตตาล็อกกลุ่มดาว หรือข้อมูลการนอนหลับเมื่อเวลาผ่านไป โดยปกติแล้ว คุณจะใช้ฐานข้อมูลเพื่อจัดเก็บข้อมูลถาวร
Room เป็นไลบรารีฐานข้อมูลที่เป็นส่วนหนึ่งของ Jetpack ของ Android Room จะช่วยจัดการงานต่างๆ ในการตั้งค่าและกำหนดค่าฐานข้อมูล และช่วยให้แอปโต้ตอบกับฐานข้อมูลได้โดยใช้การเรียกฟังก์ชันธรรมดา Room เป็นเลเยอร์การแยกข้อมูลที่อยู่เหนือฐานข้อมูล SQLite Roomและไวยากรณ์การค้นหาสำหรับการค้นหาที่ซับซ้อนยิ่งขึ้นจะใช้รูปแบบ SQLite
รูปภาพด้านล่างแสดงให้เห็นว่าฐานข้อมูล Room เหมาะสมกับสถาปัตยกรรมโดยรวมที่แนะนำในหลักสูตรนี้อย่างไร

สิ่งที่คุณควรทราบอยู่แล้ว
คุณควรคุ้นเคยกับสิ่งต่อไปนี้
- สร้างอินเทอร์เฟซผู้ใช้ (UI) พื้นฐานสำหรับแอป Android
- การใช้กิจกรรม Fragment และ View
- การไปยังส่วนย่อยต่างๆ และการใช้ Safe Args (ปลั๊กอิน Gradle) เพื่อส่งข้อมูลระหว่างส่วนย่อย
- ดูโมเดล โรงงาน View-Model และ
LiveDataรวมถึงผู้สังเกตการณ์ หัวข้อเกี่ยวกับคอมโพเนนต์สถาปัตยกรรมเหล่านี้จะอยู่ใน Codelab ก่อนหน้านี้ในหลักสูตรนี้ - ความเข้าใจพื้นฐานเกี่ยวกับฐานข้อมูล SQL และภาษา SQLite ดูภาพรวมหรือการทบทวนอย่างรวดเร็วได้ที่ข้อมูลเบื้องต้นเกี่ยวกับ SQLite
สิ่งที่คุณจะได้เรียนรู้
- วิธีสร้างและโต้ตอบกับฐานข้อมูล
Roomเพื่อคงข้อมูลไว้ - วิธีสร้างคลาสข้อมูลที่กำหนดตารางในฐานข้อมูล
- วิธีใช้ Data Access Object (DAO) เพื่อแมปฟังก์ชัน Kotlin กับการค้นหา SQL
- วิธีทดสอบว่าฐานข้อมูลทํางานหรือไม่
สิ่งที่คุณต้องดำเนินการ
- สร้างฐานข้อมูล
Roomที่มีอินเทอร์เฟซสำหรับข้อมูลการนอนหลับในแต่ละคืน - ทดสอบฐานข้อมูลโดยใช้การทดสอบที่ให้ไว้
ใน Codelab นี้ คุณจะได้สร้างส่วนฐานข้อมูลของแอปที่ติดตามคุณภาพการนอนหลับ แอปใช้ฐานข้อมูลเพื่อจัดเก็บข้อมูลการนอนหลับเมื่อเวลาผ่านไป
แอปมี 2 หน้าจอซึ่งแสดงด้วย Fragment ดังที่แสดงในรูปภาพด้านล่าง
หน้าจอแรกที่แสดงทางด้านซ้ายมีปุ่มสำหรับเริ่มและหยุดการติดตาม หน้าจอจะแสดงข้อมูลการนอนหลับทั้งหมดของผู้ใช้ ปุ่มล้างจะลบข้อมูลทั้งหมดที่แอปเก็บรวบรวมไว้สำหรับผู้ใช้ออกอย่างถาวร
หน้าจอที่ 2 ซึ่งแสดงทางด้านขวาใช้สำหรับเลือกคะแนนคุณภาพการนอนหลับ ในแอป การจัดประเภทจะแสดงเป็นตัวเลข แอปจะแสดงทั้งไอคอนใบหน้าและค่าเทียบเท่าที่เป็นตัวเลขเพื่อวัตถุประสงค์ในการพัฒนา
โฟลว์ของผู้ใช้มีดังนี้
- ผู้ใช้เปิดแอปและเห็นหน้าจอการติดตามการนอนหลับ
- ผู้ใช้แตะปุ่มเริ่ม ซึ่งจะบันทึกเวลาเริ่มต้นและแสดงเวลาดังกล่าว ปุ่มเริ่มจะปิดใช้ และปุ่มหยุดจะเปิดใช้
- ผู้ใช้แตะปุ่มหยุด ซึ่งจะบันทึกเวลาสิ้นสุดและเปิดหน้าจอคุณภาพการนอนหลับ
- ผู้ใช้เลือกไอคอนคุณภาพการนอนหลับ หน้าจอจะปิดลง และหน้าจอการติดตามจะแสดงเวลาสิ้นสุดการนอนหลับและคุณภาพการนอนหลับ ปุ่มหยุดจะปิดใช้และปุ่มเริ่มจะเปิดใช้ แอปพร้อมสำหรับคืนถัดไปแล้ว
- ปุ่มล้างจะเปิดใช้เมื่อใดก็ตามที่มีข้อมูลในฐานข้อมูล เมื่อผู้ใช้แตะปุ่มล้าง ระบบจะลบข้อมูลทั้งหมดของผู้ใช้โดยไม่มีการกู้คืนใดๆ และไม่มีข้อความ "คุณแน่ใจไหม"
แอปนี้ใช้สถาปัตยกรรมที่เรียบง่าย ดังที่แสดงด้านล่างในบริบทของสถาปัตยกรรมแบบเต็ม แอปใช้เฉพาะคอมโพเนนต์ต่อไปนี้
- ตัวควบคุม UI
- ดูโมเดลและ
LiveData - ฐานข้อมูล Room
ขั้นตอนที่ 1: ดาวน์โหลดและเรียกใช้แอปเริ่มต้น
- ดาวน์โหลดแอป TrackMySleepQuality-Starter จาก GitHub
- สร้างและเรียกใช้แอป แอปจะแสดง UI สำหรับ
SleepTrackerFragmentFragment แต่ไม่มีข้อมูล ปุ่มไม่ตอบสนองต่อการแตะ
ขั้นตอนที่ 2: ตรวจสอบแอปเริ่มต้น
- ดูไฟล์ Gradle ดังนี้
- ไฟล์ Gradle ของโปรเจ็กต์
ในไฟล์build.gradleระดับโปรเจ็กต์ ให้สังเกตตัวแปรที่ระบุเวอร์ชันของไลบรารี เวอร์ชันที่ใช้ในแอปเริ่มต้นทำงานร่วมกันได้ดีและทำงานได้ดีกับแอปนี้ เมื่อคุณทำ Codelab นี้เสร็จแล้ว Android Studio อาจแจ้งให้คุณอัปเดตเวอร์ชันบางรายการ คุณเลือกได้ว่าจะอัปเดตหรือใช้เวอร์ชันที่มีอยู่ในแอปต่อไป หากพบข้อผิดพลาดในการคอมไพล์ที่ "แปลก" ให้ลองใช้ชุดค่าผสมของเวอร์ชันไลบรารีที่แอปโซลูชันสุดท้ายใช้ - ไฟล์ Gradle ของโมดูล โปรดสังเกตทรัพยากร Dependency ที่ระบุไว้สำหรับไลบรารี Android Jetpack ทั้งหมด รวมถึง
Roomและทรัพยากร Dependency สำหรับโครูทีน
- ดูแพ็กเกจและ UI แอปมีโครงสร้างตามฟังก์ชันการทำงาน แพ็กเกจประกอบด้วยไฟล์ตัวยึดตำแหน่งที่คุณจะเพิ่มโค้ดตลอดทั้งชุดของ Codelab นี้
- แพ็กเกจ
databaseสำหรับโค้ดทั้งหมดที่เกี่ยวข้องกับฐานข้อมูลRoom - แพ็กเกจ
sleepqualityและsleeptrackerมี Fragment, View Model และ View Model Factory สำหรับแต่ละหน้าจอ
- ดู
Util.ktไฟล์ซึ่งมีฟังก์ชันที่จะช่วยแสดงข้อมูลคุณภาพการนอนหลับ โค้ดบางส่วนถูกแสดงความคิดเห็นเนื่องจากอ้างอิงถึง ViewModel ที่คุณสร้างในภายหลัง - ดูโฟลเดอร์ androidTest (
SleepDatabaseTest.kt) คุณจะใช้การทดสอบนี้เพื่อยืนยันว่าฐานข้อมูลทำงานได้ตามที่ต้องการ
ใน Android ข้อมูลจะแสดงในคลาสข้อมูล และจะเข้าถึงและแก้ไขข้อมูลได้โดยใช้การเรียกฟังก์ชัน อย่างไรก็ตาม ในโลกของฐานข้อมูล คุณต้องมีเอนทิตีและคําค้นหา
- เอนทิตีแสดงถึงออบเจ็กต์หรือแนวคิด รวมถึงพร็อพเพอร์ตี้ของออบเจ็กต์หรือแนวคิดนั้นๆ เพื่อจัดเก็บไว้ในฐานข้อมูล คลาสเอนทิตีจะกำหนดตาราง และแต่ละอินสแตนซ์ของคลาสนั้นจะแสดงแถวในตาราง แต่ละพร็อพเพอร์ตี้จะกำหนดคอลัมน์ ในแอปของคุณ เอนทิตีจะเก็บข้อมูลเกี่ยวกับการนอนหลับในคืนหนึ่งๆ
- การค้นหาคือคำขอข้อมูลจากตารางฐานข้อมูลหรือชุดตาราง หรือคำขอให้ดำเนินการกับข้อมูล คำค้นหาที่พบบ่อยคือคำค้นหาสำหรับการรับ การแทรก และการอัปเดตเอนทิตี เช่น คุณสามารถค้นหาคืนที่นอนหลับทั้งหมดที่บันทึกไว้ โดยจัดเรียงตามเวลาเริ่มต้น
Room จะทำงานหนักทั้งหมดให้คุณเพื่อเปลี่ยนจากคลาสข้อมูล Kotlin เป็นเอนทิตีที่จัดเก็บไว้ในตาราง SQLite ได้ และเปลี่ยนจากประกาศฟังก์ชันเป็นการค้นหา SQL
คุณต้องกำหนดเอนทิตีแต่ละรายการเป็นคลาสข้อมูลที่อธิบายประกอบ และการโต้ตอบเป็นอินเทอร์เฟซที่อธิบายประกอบ ซึ่งก็คือออบเจ็กต์การเข้าถึงข้อมูล (DAO) Room ใช้คลาสที่มีคำอธิบายประกอบเหล่านี้เพื่อสร้างตารางในฐานข้อมูล และการค้นหาที่ทำงานในฐานข้อมูล

ขั้นตอนที่ 1: สร้างเอนทิตี SleepNight
ในงานนี้ คุณจะกำหนดการนอนหลับ 1 คืนเป็นคลาสข้อมูลที่อธิบายประกอบ
สำหรับการนอนหลับ 1 คืน คุณต้องบันทึกเวลาเริ่มต้น เวลาสิ้นสุด และการให้คะแนนคุณภาพ
และคุณต้องมีรหัสเพื่อระบุตัวตนของคืนนั้นๆ โดยไม่ซ้ำกัน
- ใน
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เป็นคีย์หลัก ให้ใส่คำอธิบายประกอบพร็อพเพอร์ตี้nightIdด้วย@PrimaryKeyตั้งค่าพารามิเตอร์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
สำหรับฐานข้อมูลเครื่องมือติดตามการนอนหลับของคืนที่นอนหลับ คุณต้องทำสิ่งต่อไปนี้ได้
- แทรกคืนใหม่
- อัปเดตการแข่งขันที่กำลังดำเนินการเพื่ออัปเดตเวลาสิ้นสุดและการจัดประเภทคุณภาพ
- รับคืนที่เฉพาะเจาะจงตามคีย์
- รับทุกคืนเพื่อให้คุณแสดงได้
- ดูคืนล่าสุด
- ลบรายการทั้งหมดในฐานข้อมูล
ขั้นตอนที่ 1: สร้าง SleepDatabase DAO
- เปิด
SleepDatabaseDao.ktในdatabase - โปรดทราบว่า
interfaceSleepDatabaseDaoมีคำอธิบายประกอบเป็น@DaoDAO ทั้งหมดต้องมีคำอธิบายประกอบด้วยคีย์เวิร์ด@Dao
@Dao
interface SleepDatabaseDao {}- เพิ่ม
@Insertคำอธิบายประกอบในส่วนเนื้อหาของอินเทอร์เฟซ ใต้@Insertให้เพิ่มฟังก์ชันinsert()ที่ใช้อินสแตนซ์ของคลาสEntitySleepNightเป็นอาร์กิวเมนต์
เท่านี้ก็เรียบร้อยRoomจะสร้างโค้ดที่จำเป็นทั้งหมดเพื่อแทรกSleepNightลงในฐานข้อมูล เมื่อเรียกใช้insert()จากโค้ด KotlinRoomจะเรียกใช้การค้นหา SQL เพื่อแทรกเอนทิตีลงในฐานข้อมูล (หมายเหตุ: คุณตั้งชื่อฟังก์ชันเป็นอะไรก็ได้)
@Insert
fun insert(night: SleepNight)- เพิ่ม
@Updateคำอธิบายประกอบที่มีฟังก์ชันupdate()สำหรับSleepNightเอนทิตีที่อัปเดตคือเอนทิตีที่มีคีย์เดียวกันกับคีย์ที่ส่งเข้ามา คุณอัปเดตพร็อพเพอร์ตี้อื่นๆ ของเอนทิตีได้บางส่วนหรือทั้งหมด
@Update
fun update(night: SleepNight)ฟังก์ชันการทำงานที่เหลือไม่มีคำอธิบายประกอบที่สะดวก คุณจึงต้องใช้คำอธิบายประกอบ @Query และระบุการค้นหา SQLite
- เพิ่มคำอธิบายประกอบ
@Queryด้วยฟังก์ชันget()ที่ใช้อาร์กิวเมนต์LongkeyและแสดงผลSleepNightที่อนุญาตให้เป็นค่าว่าง คุณจะเห็นข้อผิดพลาดสำหรับพารามิเตอร์ที่ขาดหายไป
@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จะลบรายการ 1 รายการ และคุณสามารถใช้@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เป็นLiveDataRoomจะอัปเดต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ให้กำหนดเมธอดหรือพร็อพเพอร์ตี้แบบนามธรรมที่ส่งคืนSleepDatabaseDaoRoomจะสร้างเนื้อหาให้คุณ - คุณต้องมีฐานข้อมูล
Roomเพียงอินสแตนซ์เดียวสำหรับทั้งแอป ดังนั้นให้สร้างRoomDatabaseเป็น Singleton - ใช้เครื่องมือสร้างฐานข้อมูลของ
Roomเพื่อสร้างฐานข้อมูลเฉพาะในกรณีที่ไม่มีฐานข้อมูล ไม่เช่นนั้น ให้คืนค่าฐานข้อมูลที่มีอยู่
ขั้นตอนที่ 1: สร้างฐานข้อมูล
- เปิด
SleepDatabase.ktในdatabase - ในไฟล์ ให้สร้าง
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คุณมี DAO ได้หลายรายการ
abstract val sleepDatabaseDao: SleepDatabaseDao- จากนั้นกำหนด
companionออบเจ็กต์ ออบเจ็กต์คู่ช่วยให้ไคลเอ็นต์เข้าถึงเมธอดสำหรับการสร้างหรือรับฐานข้อมูลได้โดยไม่ต้องสร้างอินสแตนซ์ของคลาส เนื่องจากคลาสนี้มีจุดประสงค์เพียงอย่างเดียวคือการจัดเตรียมฐานข้อมูล จึงไม่มีเหตุผลที่จะต้องสร้างอินสแตนซ์ของคลาสนี้
companion object {}- ภายในออบเจ็กต์
companionให้ประกาศตัวแปรส่วนตัวที่อนุญาตให้เป็น NullINSTANCEสำหรับฐานข้อมูลและเริ่มต้นเป็นnullตัวแปรINSTANCEจะเก็บข้อมูลอ้างอิงไปยังฐานข้อมูลเมื่อมีการสร้างฐานข้อมูล ซึ่งจะช่วยให้คุณไม่ต้องเปิดการเชื่อมต่อกับฐานข้อมูลซ้ำๆ ซึ่งมีค่าใช้จ่ายสูง
ใส่คำอธิบายประกอบ INSTANCE ด้วย @Volatile ระบบจะไม่แคชค่าของตัวแปรที่เปลี่ยนแปลงได้ และการเขียนและการอ่านทั้งหมดจะดำเนินการในหน่วยความจำหลัก ซึ่งจะช่วยให้มั่นใจได้ว่าค่าของ INSTANCE จะเป็นข้อมูลล่าสุดและเหมือนกันเสมอสำหรับทุกเธรดการดำเนินการ ซึ่งหมายความว่าการเปลี่ยนแปลงที่เธรดหนึ่งทำกับ INSTANCE จะปรากฏต่อเธรดอื่นๆ ทั้งหมดทันที และคุณจะไม่เจอกรณีที่เธรด 2 เธรดอัปเดตเอนทิตีเดียวกันในแคช ซึ่งจะทำให้เกิดปัญหา
@Volatile
private var INSTANCE: SleepDatabase? = null- ที่ด้านล่าง
INSTANCEซึ่งยังอยู่ภายในออบเจ็กต์companionให้กำหนดgetInstance()เมธอดที่มีพารามิเตอร์Contextที่เครื่องมือสร้างฐานข้อมูลจะต้องใช้ แสดงผลประเภทSleepDatabaseคุณจะเห็นข้อผิดพลาดเนื่องจากgetInstance()ยังไม่แสดงผลอะไร
fun getInstance(context: Context): SleepDatabase {}- เพิ่มบล็อก
synchronized{}ในgetInstance()ส่งthisเพื่อให้คุณเข้าถึงบริบทได้
ชุดข้อความหลายชุดอาจขออินสแตนซ์ฐานข้อมูลพร้อมกัน ซึ่งจะทำให้มีฐานข้อมูล 2 รายการแทนที่จะเป็น 1 รายการ ปัญหานี้ไม่น่าจะเกิดขึ้นในแอปตัวอย่างนี้ แต่ก็อาจเกิดขึ้นได้ในแอปที่ซับซ้อนกว่า การห่อโค้ดเพื่อให้ได้ฐานข้อมูลใน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 ดังนั้นคุณจึงต้องเรียกใช้การทดสอบบนอุปกรณ์จริงหรืออุปกรณ์เสมือน แน่นอนว่าคุณยังสร้างและเรียกใช้การทดสอบหน่วยอย่างเดียวที่ไม่เกี่ยวข้องกับเฟรมเวิร์ก Android ได้ด้วย
- ใน Android Studio ให้เปิดไฟล์ SleepDatabaseTest ในโฟลเดอร์ androidTest
- หากต้องการยกเลิกการแสดงความคิดเห็นในโค้ด ให้เลือกโค้ดที่แสดงความคิดเห็นทั้งหมด แล้วกดแป้นพิมพ์ลัด
Cmd+/หรือControl+/ - ดูไฟล์
ต่อไปนี้คือภาพรวมโดยย่อของโค้ดการทดสอบ เนื่องจากเป็นโค้ดอีกส่วนหนึ่งที่คุณนำกลับมาใช้ใหม่ได้
SleepDabaseTestเป็นชั้นเรียนทดสอบ- คำอธิบายประกอบ
@RunWithระบุตัวเรียกใช้การทดสอบ ซึ่งเป็นโปรแกรมที่ตั้งค่าและเรียกใช้การทดสอบ - ในระหว่างการตั้งค่า ฟังก์ชันที่อธิบายประกอบด้วย
@Beforeจะได้รับการดำเนินการ และจะสร้างSleepDatabaseในหน่วยความจำด้วยSleepDatabaseDao"ในหน่วยความจำ" หมายความว่าระบบจะไม่บันทึกฐานข้อมูลนี้ในระบบไฟล์ และจะลบฐานข้อมูลหลังจากที่เรียกใช้การทดสอบ - นอกจากนี้ เมื่อสร้างฐานข้อมูลในหน่วยความจำ โค้ดจะเรียกใช้เมธอดอื่นที่เฉพาะเจาะจงสำหรับการทดสอบ
allowMainThreadQueriesโดยค่าเริ่มต้น คุณจะได้รับข้อผิดพลาดหากพยายามเรียกใช้การค้นหาในเทรดหลัก วิธีนี้ช่วยให้คุณเรียกใช้การทดสอบในเทรดหลักได้ ซึ่งคุณควรทำเฉพาะในระหว่างการทดสอบเท่านั้น - ในเมธอดทดสอบที่มีคำอธิบายประกอบ
@Testคุณจะสร้าง แทรก และเรียกข้อมูลSleepNightแล้วยืนยันว่าข้อมูลเหล่านั้นเหมือนกัน หากเกิดข้อผิดพลาด ให้ส่งข้อยกเว้น ในการทดสอบจริง คุณจะมี@Testหลายวิธี - เมื่อการทดสอบเสร็จสิ้น ฟังก์ชันที่อธิบายประกอบด้วย
@Afterจะทํางานเพื่อปิดฐานข้อมูล
- คลิกขวาที่ไฟล์ทดสอบในบานหน้าต่างโปรเจ็กต์ แล้วเลือกเรียกใช้ "SleepDatabaseTest"
- หลังจากทดสอบแล้ว ให้ตรวจสอบในแผง SleepDatabaseTest ว่าการทดสอบทั้งหมดผ่านแล้ว

เนื่องจากการทดสอบทั้งหมดผ่าน คุณจึงทราบสิ่งต่างๆ ดังนี้
- ระบบจะสร้างฐานข้อมูลอย่างถูกต้อง
- คุณสามารถแทรก
SleepNightลงในฐานข้อมูลได้ - คุณจะได้รับ
SleepNightคืน SleepNightมีค่าที่ถูกต้องสำหรับคุณภาพ
โปรเจ็กต์ Android Studio: TrackMySleepQualityRoomAndTesting
เมื่อทดสอบฐานข้อมูล คุณต้องเรียกใช้เมธอดทั้งหมดที่กำหนดไว้ใน DAO หากต้องการทำการทดสอบให้เสร็จสมบูรณ์ ให้เพิ่มและเรียกใช้การทดสอบเพื่อทดสอบเมธอด DAO อื่นๆ
- กำหนดตารางเป็นคลาสข้อมูลที่มีคำอธิบายประกอบ
@Entityกำหนดพร็อพเพอร์ตี้ที่มีคำอธิบายประกอบด้วย@ColumnInfoเป็นคอลัมน์ในตาราง - กำหนดออบเจ็กต์การเข้าถึงข้อมูล (DAO) เป็นอินเทอร์เฟซที่มีคำอธิบายประกอบ
@DaoDAO จะแมปฟังก์ชัน Kotlin กับการค้นหาฐานข้อมูล - ใช้คำอธิบายประกอบเพื่อกำหนดฟังก์ชัน
@Insert,@Deleteและ@Update - ใช้
@Queryคำอธิบายประกอบที่มีสตริงการค้นหา SQLite เป็นพารามิเตอร์สำหรับการค้นหาอื่นๆ - สร้างคลาส Abstract ที่มีฟังก์ชัน
getInstance()ซึ่งแสดงผลฐานข้อมูล - ใช้การทดสอบที่วัดผลเพื่อทดสอบว่าฐานข้อมูลและ DAO ทำงานตามที่คาดไว้ คุณใช้การทดสอบที่ให้ไว้เป็นเทมเพลตได้
หลักสูตร Udacity:
เอกสารประกอบสำหรับนักพัฒนาแอป Android:
RoomDatabaseDatabase(คำอธิบายประกอบ)- คุณใช้การค้นหาดิบกับ
Roomได้ Roomdatabase.Builder- การฝึกอบรมการทดสอบ
SQLiteDatabaseชั้นเรียนDaoRoomไลบรารีการคงอยู่
เอกสารและบทความอื่นๆ
ส่วนนี้แสดงรายการการบ้านที่เป็นไปได้สำหรับนักเรียน/นักศึกษาที่กำลังทำ Codelab นี้เป็นส่วนหนึ่งของหลักสูตรที่สอนโดยผู้สอน ผู้สอนมีหน้าที่ดำเนินการต่อไปนี้
- มอบหมายการบ้านหากจำเป็น
- สื่อสารกับนักเรียนเกี่ยวกับวิธีส่งงานที่ได้รับมอบหมาย
- ให้คะแนนงานการบ้าน
ผู้สอนสามารถใช้คำแนะนำเหล่านี้ได้มากน้อยตามที่ต้องการ และควรมีอิสระในการมอบหมายการบ้านอื่นๆ ที่เห็นว่าเหมาะสม
หากคุณกำลังทำ Codelab นี้ด้วยตนเอง โปรดใช้แบบฝึกหัดเหล่านี้เพื่อทดสอบความรู้ของคุณ
ตอบคำถามต่อไปนี้
คำถามที่ 1
คุณจะระบุว่าคลาสแสดงถึงเอนทิตีที่จะจัดเก็บในRoomฐานข้อมูลได้อย่างไร
- ขยายเวลาชั้นเรียน
DatabaseEntity - ใส่คำอธิบายประกอบในชั้นเรียนด้วย
@Entity - ใส่คำอธิบายประกอบในชั้นเรียนด้วย
@Database - ขยายคลาส
RoomEntityและใส่คำอธิบายประกอบในคลาสด้วย@Room
คำถามที่ 2
DAO (Data Access Object) คืออินเทอร์เฟซที่ Room ใช้เพื่อแมปฟังก์ชัน Kotlin กับการค้นหาฐานข้อมูล
คุณจะระบุว่าอินเทอร์เฟซแสดงถึง DAO สำหรับฐานข้อมูล Room ได้อย่างไร
- ขยายอินเทอร์เฟซ
RoomDAO - ทำให้อินเทอร์เฟซขยาย
EntityDaoจากนั้นใช้เมธอดDaoConnection() - ใส่คำอธิบายประกอบในอินเทอร์เฟซด้วย
@Dao - ใส่คำอธิบายประกอบในอินเทอร์เฟซด้วย
@RoomConnection
คำถามที่ 3
ข้อความใดต่อไปนี้เป็นจริงเกี่ยวกับRoomฐานข้อมูล เลือกได้มากกว่า 1 ข้อ
- คุณกำหนดตารางสำหรับฐานข้อมูล
Roomเป็นคลาสข้อมูลที่อธิบายประกอบได้ - หากคุณส่งคืน
LiveDataจากการค้นหาRoomจะอัปเดตLiveDataให้คุณหากLiveDataมีการเปลี่ยนแปลง - ฐานข้อมูล
Roomแต่ละฐานข้อมูลต้องมี DAO เพียง 1 รายการเท่านั้น - หากต้องการระบุคลาสเป็น
Roomฐานข้อมูล ให้สร้างเป็นคลาสย่อยของRoomDatabaseและใส่คำอธิบายประกอบด้วย@Database
คำถามที่ 4
คุณใช้คำอธิบายประกอบใดต่อไปนี้ในอินเทอร์เฟซ @Dao ได้ เลือกได้มากกว่า 1 ข้อ
@Get@Update@Insert@Query
คำถามที่ 5
คุณจะยืนยันได้อย่างไรว่าฐานข้อมูลทำงานได้ เลือกได้มากกว่า 1 ข้อ
- เขียนการทดสอบแบบมีเครื่องมือ
- เขียนและเรียกใช้แอปต่อไปจนกว่าจะแสดงข้อมูล
- แทนที่การเรียกเมธอดในอินเทอร์เฟซ DAO ด้วยการเรียกเมธอดที่เทียบเท่าในคลาส
Entity - เรียกใช้ฟังก์ชัน
verifyDatabase()ที่ไลบรารีRoomมีให้
เริ่มบทเรียนถัดไป:
ดูลิงก์ไปยัง Codelab อื่นๆ ในหลักสูตรนี้ได้ที่หน้า Landing Page ของ Codelab หลักพื้นฐานของ Android Kotlin