Codelab นี้เป็นส่วนหนึ่งของหลักสูตรพื้นฐานเกี่ยวกับ Kotlin ใน Android คุณจะได้รับประโยชน์สูงสุดจากหลักสูตรนี้ หากทํางานผ่าน Codelab ตามลําดับ Codelab ของหลักสูตรทั้งหมดจะแสดงอยู่ในหน้า Landing Page ของ Codelab ของ Android Kotlin Fundamentals
บทนำ
แอปส่วนใหญ่มีข้อมูลที่ต้องเก็บไว้แม้ว่าผู้ใช้จะปิดแอปไปแล้ว เช่น แอปอาจจัดเก็บเพลย์ลิสต์ คลังรายการเกม บันทึกค่าใช้จ่ายและรายได้ แคตตาล็อกกลุ่มดาว หรือข้อมูลการนอนหลับเมื่อเวลาผ่านไป โดยทั่วไป คุณจะต้องใช้ฐานข้อมูลเพื่อจัดเก็บข้อมูลถาวร
Room
คือไลบรารีฐานข้อมูลที่เป็นส่วนหนึ่งของ Jetpack ของ Android Room
จัดการขั้นตอนการตั้งค่าและกําหนดค่าฐานข้อมูล และทําให้แอปสามารถโต้ตอบกับฐานข้อมูลโดยใช้การเรียกฟังก์ชันทั่วไป ขั้นสูง Room
คือเลเยอร์นามธรรมที่ด้านบนของฐานข้อมูล SQLite Room
เข้ากับรูปแบบของคําศัพท์และไวยากรณ์ของคําค้นหาสําหรับการค้นหาที่ซับซ้อนมากขึ้นตามโมเดล SQLite
รูปภาพด้านล่างแสดงลักษณะที่ฐานข้อมูล Room
สอดคล้องกับสถาปัตยกรรมโดยรวมที่แนะนําในหลักสูตรนี้
สิ่งที่ควรทราบอยู่แล้ว
คุณควรทําความคุ้นเคยกับสิ่งต่อไปนี้
- การสร้างอินเทอร์เฟซผู้ใช้ (UI) พื้นฐานสําหรับแอป Android
- การใช้กิจกรรม ส่วนย่อย และการดู
- การไปยังส่วนต่างๆ ระหว่างส่วนย่อยและการใช้ Safe Args (ปลั๊กอิน Gradle) เพื่อส่งข้อมูลระหว่างส่วนย่อย
- ดูโมเดล โรงงานของโมเดลการดู และ
LiveData
และการสังเกตการณ์ หัวข้อคอมโพเนนต์สถาปัตยกรรมเหล่านี้รวมอยู่ใน Codelab ก่อนหน้าในหลักสูตรนี้ - ความเข้าใจเบื้องต้นเกี่ยวกับฐานข้อมูล SQL และภาษา SQLite ดู SQLite Primer เพื่อดูภาพรวมหรือการรีเฟรชอย่างรวดเร็ว
สิ่งที่คุณจะได้เรียนรู้
- วิธีสร้างและโต้ตอบกับฐานข้อมูล
Room
เพื่อคงข้อมูลไว้ - วิธีสร้างคลาสข้อมูลที่กําหนดตารางในฐานข้อมูล
- วิธีใช้ออบเจ็กต์การเข้าถึงข้อมูล (DAO) เพื่อแมปฟังก์ชัน Kotlin กับคําค้นหา SQL
- วิธีทดสอบว่าฐานข้อมูลของคุณทํางานหรือไม่
สิ่งที่คุณจะทํา
- สร้างฐานข้อมูล
Room
ด้วยอินเทอร์เฟซสําหรับข้อมูลการนอนหลับตอนกลางคืน - ทดสอบฐานข้อมูลโดยใช้การทดสอบที่มีให้
ใน Codelab นี้ คุณสร้างส่วนฐานข้อมูลของแอปที่ติดตามคุณภาพการนอนหลับ แอปใช้ฐานข้อมูลเพื่อจัดเก็บข้อมูลการนอนหลับเมื่อเวลาผ่านไป
แอปมีหน้าจอ 2 หน้าจอ ซึ่งแสดงผลด้วยส่วนย่อยตามที่แสดงในภาพด้านล่าง
หน้าจอแรกที่แสดงทางด้านซ้ายมีปุ่มให้เริ่มและหยุดการติดตาม หน้าจอแสดงข้อมูลการนอนหลับของผู้ใช้ทั้งหมด ปุ่มล้างจะลบข้อมูลทั้งหมดที่แอปรวบรวมให้กับผู้ใช้อย่างถาวร
หน้าจอที่ 2 ที่แสดงทางด้านขวาคือการเลือกคะแนนคุณภาพการนอนหลับ ในแอป ตัวเลขจะแสดงเป็นตัวเลข แอปจะแสดงทั้งไอคอนใบหน้าและตัวเลขที่เทียบเท่าเพื่อวัตถุประสงค์ในการพัฒนา
โฟลว์ผู้ใช้มีดังนี้
- ผู้ใช้เปิดแอปและนําเสนอด้วยหน้าจอติดตามการนอนหลับ
- ผู้ใช้แตะปุ่มเริ่ม ซึ่งจะบันทึกเวลาเริ่มต้นและแสดง ปุ่มเริ่มต้นปิดใช้อยู่ และปุ่มหยุดเปิดใช้งานอยู่
- ผู้ใช้แตะปุ่มหยุด ซึ่งจะบันทึกเวลาสิ้นสุดและเปิดหน้าจอคุณภาพการนอนหลับ
- ผู้ใช้เลือกไอคอนคุณภาพการนอนหลับ หน้าจอจะปิดลงและหน้าจอการติดตามจะแสดงเวลานอนและคุณภาพการนอนหลับ ปุ่มหยุดปิดใช้อยู่และปุ่มเริ่มต้นจะเปิดใช้อยู่ แอปพร้อมใช้งานสําหรับอีกคืนหนึ่ง
- ปุ่มล้างจะเปิดใช้เมื่อใดก็ตามที่มีข้อมูลในฐานข้อมูล เมื่อผู้ใช้แตะปุ่มล้างระบบจะลบข้อมูลทั้งหมดของผู้ใช้โดยไม่ออกคําสั่ง เพราะไม่มี "คุณแน่ใจหรือเรียกว่า CPD ข้อความ
แอปนี้ใช้สถาปัตยกรรมแบบง่ายดังที่แสดงด้านล่างในบริบทของสถาปัตยกรรมแบบเต็ม แอปใช้คอมโพเนนต์ต่อไปนี้เท่านั้น
- ตัวควบคุม UI
- ดูโมเดลและ
LiveData
- ฐานข้อมูลห้องแชท
ขั้นตอนที่ 1: ดาวน์โหลดและเรียกใช้แอปเริ่มต้น
- ดาวน์โหลดแอป TrackMySleepคุณภาพ-Starter จาก GitHub
- สร้างและเรียกใช้แอป แอปจะแสดง UI สําหรับส่วนย่อย
SleepTrackerFragment
แต่ไม่มีข้อมูล ปุ่มจะไม่ตอบสนองต่อการแตะ
ขั้นตอนที่ 2: ตรวจสอบแอปเริ่มต้น
- ดูไฟล์ Gradle
- ไฟล์ Gradle โปรเจ็กต์
ในไฟล์build.gradle
ระดับโปรเจ็กต์ ให้สังเกตตัวแปรที่ระบุเวอร์ชันของไลบรารี เวอร์ชันที่ใช้ในแอปเริ่มต้นทํางานร่วมกันได้ดีและทํางานร่วมกับแอปนี้ได้ดี เมื่อคุณดําเนินการ Codelab นี้เสร็จสิ้น Android Studio อาจแจ้งให้คุณอัปเดตบางเวอร์ชัน ทั้งนี้ขึ้นอยู่กับว่าคุณต้องการอัปเดตหรือใช้งานเวอร์ชันที่อยู่ในแอปต่อไป หากพบข้อผิดพลาดในการรวบรวม &&tt;strange" ให้ลองใช้ไลบรารีเวอร์ชันต่างๆ ที่แอปโซลูชันสุดท้ายใช้ร่วมกัน - ไฟล์ Gradle ของโมดูล ดูทรัพยากร Dependency ที่ระบุสําหรับไลบรารี Android Jetpack ทั้งหมด รวมถึง
Room
และทรัพยากร Dependency สําหรับ Coroutine
- ดูที่แพ็กเกจและ UI แอปมีโครงสร้างตามฟังก์ชันการทํางาน แพ็กเกจนี้มีไฟล์ตัวยึดตําแหน่งที่คุณจะเพิ่มโค้ดทั่วทั้ง Codelab ชุดนี้
- แพ็กเกจ
database
สําหรับโค้ดทั้งหมดที่เกี่ยวข้องกับฐานข้อมูลRoom
- แพ็กเกจ
sleepquality
และsleeptracker
มีส่วนย่อย รูปแบบการดู และการดูโมเดลโรงงานสําหรับแต่ละหน้าจอ
- ดูที่ไฟล์
Util.kt
ซึ่งมีฟังก์ชันที่จะช่วยแสดงข้อมูลคุณภาพการนอนหลับ โค้ดบางรายการได้รับการแสดงความคิดเห็นเนื่องจากอ้างอิงโมเดลข้อมูลพร็อพเพอร์ตี้ที่คุณสร้างในภายหลัง - ดูโฟลเดอร์ 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) DAO นําเสนอวิธีที่สะดวกสําหรับการแทรก ลบ และอัปเดตฐานข้อมูลใน Android
เมื่อใช้ฐานข้อมูล Room
คุณจะค้นหาฐานข้อมูลได้โดยกําหนดและเรียกใช้ฟังก์ชัน Kotlin ในโค้ด ฟังก์ชัน Kotlin เหล่านี้จะแมปกับคําค้นหา SQL คุณกําหนดการแมปเหล่านั้นใน DAO โดยใช้คําอธิบายประกอบ และ Room
จะสร้างโค้ดที่จําเป็น
ลองคิดว่า DAO คือการกําหนดอินเทอร์เฟซที่กําหนดเองสําหรับการเข้าถึงฐานข้อมูลของคุณ
สําหรับการดําเนินการฐานข้อมูลทั่วไป ไลบรารี Room
จะมีคําอธิบายประกอบความสะดวก เช่น @Insert
, @Delete
และ @Update
สําหรับสิ่งอื่นๆ ทั้งหมดจะมีคําอธิบายประกอบ @Query
คุณเขียนคําค้นหาที่ SQLite รองรับได้
นอกจากนี้ คอมไพเลอร์จะตรวจสอบการค้นหา SQL เพื่อหาข้อผิดพลาดทางไวยากรณ์และเป็นโบนัสเพิ่มเติมเมื่อสร้างคําค้นหาใน Android Studio
คุณต้องดําเนินการต่อไปนี้ในฐานข้อมูลเครื่องมือติดตามการนอนหลับของคืน
- แทรกคืนใหม่
- อัปเดตคืนที่มีอยู่เพื่ออัปเดตเวลาสิ้นสุดและคะแนนคุณภาพ
- รับคืนที่เฉพาะเจาะจงตามคีย์ของสถานที่นั้น
- รับคืนทั้งหมดเพื่อให้คุณแสดงได้
- ดูข้อมูลเมื่อคืนล่าสุด
- ลบรายการทั้งหมดในฐานข้อมูล
ขั้นตอนที่ 1: สร้าง SleepDatabase DAO
- ในแพ็กเกจ
database
ให้เปิดSleepDatabaseDao.kt
- โปรดสังเกตว่า
interface
SleepDatabaseDao
มีคําอธิบายประกอบ@Dao
DAO ทั้งหมดต้องมีคําอธิบายประกอบด้วยคีย์เวิร์ด@Dao
@Dao
interface SleepDatabaseDao {}
- ในเนื้อหาของอินเทอร์เฟซ ให้เพิ่มคําอธิบายประกอบ
@Insert
ใต้@Insert
ให้เพิ่มฟังก์ชันinsert()
ที่มีอินสแตนซ์ของคลาสEntity
SleepNight
เป็นอาร์กิวเมนต์
เท่านี้ก็เรียบร้อยRoom
จะสร้างโค้ดที่จําเป็นทั้งหมดเพื่อแทรกSleepNight
ลงในฐานข้อมูล เมื่อเรียกใช้insert()
จากโค้ด KotlinRoom
จะเรียกใช้การค้นหา SQL เพื่อแทรกเอนทิตีลงในฐานข้อมูล (หมายเหตุ: คุณจะเรียกฟังก์ชันใดก็ได้ตามต้องการ)
@Insert
fun insert(night: SleepNight)
- เพิ่มคําอธิบายประกอบ
@Update
ที่มีฟังก์ชันupdate()
สําหรับSleepNight
รายการเดียว เอนทิตีที่อัปเดต # คือเอนทิตีที่มีคีย์เดียวกันกับคีย์ที่ส่ง คุณอัปเดตพร็อพเพอร์ตี้อื่นๆ บางส่วนหรือทั้งหมดได้
@Update
fun update(night: SleepNight)
ไม่มีคําอธิบายประกอบอํานวยความสะดวกสําหรับฟังก์ชันการทํางานที่เหลืออยู่ คุณจึงต้องใช้คําอธิบายประกอบ @Query
และให้ข้อมูลการค้นหา SQLite
- เพิ่มคําอธิบายประกอบ
@Query
ด้วยฟังก์ชันget()
ที่ใช้อาร์กิวเมนต์Long
key
และแสดงผลSleepNight
เป็นค่าว่าง คุณจะเห็นข้อผิดพลาดสําหรับพารามิเตอร์ที่ขาดหายไป
@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()
และการค้นหา SQL ไปยังDELETE
ทุกรายการจากdaily_sleep_quality_table
การค้นหานี้จะไม่ลบตารางเอง
คําอธิบายประกอบ@Delete
จะลบ 1 รายการ แต่คุณใช้@Delete
และระบุรายการของคืนที่ต้องการลบได้ ข้อด้อยคือคุณจะต้องดึงข้อมูลหรือรู้สิ่งที่อยู่ในตาราง คําอธิบายประกอบ@Delete
เหมาะสําหรับการลบรายการที่เจาะจง แต่ไม่เหมาะสําหรับการลบรายการทั้งหมดออกจากตาราง
@Query("DELETE FROM daily_sleep_quality_table")
fun clear()
- เพิ่ม
@Query
ที่มีฟังก์ชันgetTonight()
ทําให้SleepNight
แสดงผลโดยgetTonight()
เป็นค่าว่างเพื่อให้ฟังก์ชันจัดการกับกรณีที่ตารางว่างเปล่าได้ (ตารางจะว่างเปล่าที่ตอนต้นและหลังจากที่ล้างข้อมูลแล้ว)
หากต้องการรับ "night" จากฐานข้อมูล ให้เขียนคําค้นหา SQLite ที่แสดงองค์ประกอบแรกของรายการลําดับที่nightId
เรียงลําดับจากมากไปหาน้อย ใช้LIMIT 1
เพื่อแสดงองค์ประกอบเพียง 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
คลาสนี้มี 1 วิธีสร้างอินสแตนซ์ของฐานข้อมูลได้หากไม่มีฐานข้อมูล หรือส่งคืนการอ้างอิงไปยังฐานข้อมูลที่มีอยู่
การรับฐานข้อมูล Room
มีความเกี่ยวข้องเล็กน้อย ดังนั้นขั้นตอนทั่วไปก่อนที่จะเริ่มโค้ดมีดังนี้
- สร้างชั้นเรียน
public abstract
ที่extends RoomDatabase
ชั้นเรียนนี้ เราจะทําหน้าที่เป็นผู้ถือฐานข้อมูล ชั้นเรียนนี้เป็นนามธรรมเนื่องจากRoom
จะสร้างการใช้งานให้คุณ - เพิ่มหมายเหตุในชั้นเรียนด้วย
@Database
ในอาร์กิวเมนต์ ให้ประกาศเอนทิตีสําหรับฐานข้อมูลและกําหนดหมายเลขเวอร์ชัน - ภายในออบเจ็กต์
companion
ให้กําหนดเมธอดนามธรรมหรือพร็อพเพอร์ตี้ที่ส่งคืนSleepDatabaseDao
Room
จะสร้างเนื้อหาให้คุณ - คุณต้องใช้ฐานข้อมูล
Room
เพียง 1 รายการสําหรับทั้งแอป ดังนั้นให้ใช้RoomDatabase
เป็นรายการเดียว - ใช้เครื่องมือสร้างฐานข้อมูลของ
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
คุณมี DAO ได้หลายรายการ
abstract val sleepDatabaseDao: SleepDatabaseDao
- ด้านล่าง ให้กําหนดออบเจ็กต์
companion
ออบเจ็กต์ที่ใช้ร่วมกันจะช่วยให้ไคลเอ็นต์เข้าถึงวิธีสร้างหรือรับฐานข้อมูลโดยไม่ต้องเรียกใช้คลาสทันที เนื่องจากวัตถุประสงค์เดียวของคลาสนี้คือการระบุฐานข้อมูล จึงไม่มีเหตุผลที่ต้องเรียกใช้ฐานข้อมูลนี้
companion object {}
- ในออบเจ็กต์
companion
ให้ประกาศตัวแปรส่วนตัวที่ไม่มีข้อมูลINSTANCE
สําหรับฐานข้อมูลและเริ่มต้นตัวแปรเป็นnull
ตัวแปรINSTANCE
จะเก็บการอ้างอิงไปยังฐานข้อมูลเมื่อสร้างขึ้นแล้ว ซึ่งจะช่วยให้คุณไม่ต้องเปิดการเชื่อมต่อฐานข้อมูลบ่อยๆ ซึ่งมีค่าใช้จ่ายสูง
เพิ่มคําอธิบายประกอบ INSTANCE
ด้วย @Volatile
ค่าของตัวแปรผันผวนจะไม่ถูกแคช และการเขียนและการอ่านทั้งหมดจะดําเนินการจากและไปยังหน่วยความจําหลัก การดําเนินการนี้จะช่วยให้ค่าของ INSTANCE
เป็นปัจจุบันและเหมือนกันกับชุดข้อความการดําเนินการทั้งหมด ซึ่งหมายความว่าการเปลี่ยนแปลงที่ทําโดยชุดข้อความหนึ่งไปยัง INSTANCE
จะปรากฏต่อชุดข้อความอื่นๆ ทั้งหมดทันที และคุณไม่มีสถานการณ์ที่เกิดขึ้น เช่น ชุดข้อความ 2 รายการอัปเดตเอนทิตีเดียวกันในแคช ซึ่งจะทําให้เกิดปัญหา
@Volatile
private var INSTANCE: SleepDatabase? = null
- ด้านล่าง
INSTANCE
ซึ่งยังอยู่ในออบเจ็กต์companion
ให้กําหนดเมธอดgetInstance()
ด้วยพารามิเตอร์Context
ที่เครื่องมือสร้างฐานข้อมูลจะต้องใช้ แสดงประเภทSleepDatabase
คุณจะเห็นข้อผิดพลาดเนื่องจากgetInstance()
ยังไม่ได้ส่งคืนอะไร
fun getInstance(context: Context): SleepDatabase {}
- ภายใน
getInstance()
ให้เพิ่มบล็อกsynchronized{}
ส่งผ่านในthis
เพื่อให้คุณเข้าถึงบริบทได้
ชุดข้อความหลายรายการอาจขออินสแตนซ์ฐานข้อมูลพร้อมกัน ซึ่งทําให้มีฐานข้อมูล 2 รายการแทนที่จะเป็นฐานข้อมูล 1 รายการ ปัญหานี้ไม่น่าจะเกิดขึ้นในแอปตัวอย่างนี้ แต่อาจเป็นไปได้สําหรับแอปที่ซับซ้อนขึ้น การรวมโค้ดเพื่อดึงฐานข้อมูลไปยังsynchronized
หมายความว่าจะมีการดําเนินการชุดข้อความเพียง 1 ชุดต่อครั้งเท่านั้น จึงอาจทําให้ฐานข้อมูลเริ่มต้นได้เพียงครั้งเดียว
synchronized(this) {}
- ภายในค่าที่ซิงค์ ให้คัดลอกค่าปัจจุบันของ
INSTANCE
ไปยังตัวแปรinstance
ในเครื่อง การดําเนินการนี้จะใช้ประโยชน์จากสมาร์ทแคสต์ ซึ่งใช้ได้กับตัวแปรภายในเท่านั้น
var instance = INSTANCE
- ภายในบล็อก
synchronized
,return instance
ที่ส่วนท้ายของบล็อกsynchronized
ไม่สนใจข้อผิดพลาดประเภทการคืนสินค้าที่ไม่ตรงกัน และจะไม่แสดงเป็นนัลเมื่อเสร็จสิ้น
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 ได้
- เปิดไฟล์ SleepDatabaseTest ใน Android Studio ในโฟลเดอร์ androidTest
- หากต้องการเลิกซ่อนโค้ด ให้เลือกโค้ดที่แสดงความคิดเห็นทั้งหมดแล้วกดแป้นพิมพ์ลัด
Cmd+/
หรือControl+/
- ตรวจดูไฟล์
ต่อไปนี้เป็นโค้ดการทดสอบแบบคร่าวๆ เพราะโค้ดอีกชิ้นหนึ่งที่คุณนํามาใช้ซ้ําได้มีดังนี้
SleepDabaseTest
เป็นชั้นเรียนทดสอบ- คําอธิบายประกอบ
@RunWith
จะระบุตัวดําเนินการทดสอบ ซึ่งเป็นโปรแกรมที่กําหนดและทําการทดสอบ - ระหว่างการตั้งค่า ฟังก์ชันที่มีคําอธิบายประกอบเป็น
@Before
จะดําเนินการและสร้างSleepDatabase
ในหน่วยความจําด้วยSleepDatabaseDao
"ในหน่วยความจํา"หมายความว่าฐานข้อมูลนี้จะไม่บันทึกไว้ในระบบไฟล์และจะถูกลบออกหลังจากการทดสอบทํางาน - และเมื่อสร้างฐานข้อมูลในหน่วยความจํา โค้ดจะเรียกใช้เมธอดทดสอบเฉพาะอีกอย่าง นั่นคือ
allowMainThreadQueries
โดยค่าเริ่มต้น ระบบจะแสดงข้อผิดพลาดหากคุณพยายามเรียกใช้คําค้นหาในชุดข้อความหลัก วิธีนี้จะช่วยให้คุณเรียกใช้การทดสอบในชุดข้อความหลักได้ ซึ่งทําได้เฉพาะเมื่อทดสอบ - ในการสร้างวิธีทดสอบที่มีคําอธิบายประกอบกับ
@Test
คุณจะสร้าง แทรก และเรียกข้อมูลSleepNight
แล้วยืนยันได้ว่าเป็นวิธีเดียวกัน หากมีข้อผิดพลาดเกิดขึ้น ให้มีข้อยกเว้น ในการทดสอบจริง คุณจะมี@Test
วิธีหลายวิธี - เมื่อทดสอบเสร็จแล้ว ฟังก์ชันที่มีคําอธิบายประกอบกับ
@After
จะสั่งปิดฐานข้อมูล
- คลิกขวาที่ไฟล์ทดสอบในแผงโปรเจ็กต์ แล้วเลือกเรียกใช้ 'SleepDatabaseTest'
- หลังจากทําการทดสอบแล้ว ให้ยืนยันในแผง SleepDatabaseTest ว่าการทดสอบทั้งหมดผ่านแล้ว
เนื่องจากการทดสอบทั้งหมดผ่านแล้ว คุณจึงทราบสาเหตุหลายๆ ประการดังนี้
- สร้างฐานข้อมูลอย่างถูกต้อง
- คุณสามารถแทรก
SleepNight
ในฐานข้อมูลได้ - คุณคืนค่า
SleepNight
ได้ SleepNight
มีค่าที่ถูกต้องสําหรับคุณภาพ
โปรเจ็กต์ Android Studio: TrackMySleepคุณภาพRoomAndTesting
เมื่อทดสอบฐานข้อมูล คุณต้องใช้วิธีการทั้งหมดที่กําหนดไว้ใน 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 (Data access object) คืออินเทอร์เฟซที่ Room
ใช้ในการแมปฟังก์ชัน Kotlin กับคําค้นหาของฐานข้อมูล
คุณระบุได้อย่างไรว่าอินเทอร์เฟซแสดงถึง DAO สําหรับฐานข้อมูล Room
- ขยายอินเทอร์เฟซเป็น
RoomDAO
- ทําให้อินเทอร์เฟซขยาย
EntityDao
แล้วใช้เมธอดDaoConnection()
- เพิ่มคําอธิบายประกอบให้กับอินเทอร์เฟซด้วย
@Dao
- เพิ่มคําอธิบายประกอบให้กับอินเทอร์เฟซด้วย
@RoomConnection
คำถามที่ 3
ข้อความใดเกี่ยวกับฐานข้อมูล Room
ที่เป็นจริง เลือกได้มากกว่า 1 ข้อ
- คุณจะกําหนดตารางสําหรับฐานข้อมูล
Room
เป็นคลาสข้อมูลที่มีคําอธิบายประกอบได้ - หากคุณแสดงผล
LiveData
จากคําค้นหาRoom
จะอัปเดตLiveData
ให้คุณต่อไปหากLiveData
มีการเปลี่ยนแปลง - ฐานข้อมูล
Room
แต่ละรายการต้องมี DAO และเพียงรายการเดียว - หากต้องการระบุชั้นเรียนเป็นฐานข้อมูล
Room
โปรดกําหนดให้เป็นชั้นเรียนย่อยของRoomDatabase
และใส่คําอธิบายประกอบด้วย@Database
คำถามที่ 4
คําอธิบายประกอบใดต่อไปนี้ที่คุณสามารถใช้ได้ในอินเทอร์เฟซ @Dao
เลือกได้มากกว่า 1 ข้อ
@Get
@Update
@Insert
@Query
คำถามที่ 5
คุณจะยืนยันได้อย่างไรว่าฐานข้อมูลของคุณใช้งานได้ เลือกได้มากกว่า 1 ข้อ
- เขียนการทดสอบการวัดคุม
- เขียนและเรียกใช้แอปต่อจนกว่าแอปจะแสดงข้อมูล
- แทนที่การเรียกไปยังเมธอดในอินเทอร์เฟซ DAO ด้วยการเรียกเมธอดที่เทียบเท่ากันใน
Entity
คลาส - เรียกใช้ฟังก์ชัน
verifyDatabase()
ที่ได้จากไลบรารีRoom
เริ่มบทเรียนถัดไป:
สําหรับลิงก์ไปยัง Codelab อื่นๆ ในหลักสูตรนี้ โปรดดูหน้า Landing Page ของ Codelab ของ Android Kotlin Fundamentals