Android Kotlin Fundamentals 06.1: สร้างฐานข้อมูลห้อง

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: ดาวน์โหลดและเรียกใช้แอปเริ่มต้น

  1. ดาวน์โหลดแอป TrackMySleepคุณภาพ-Starter จาก GitHub
  2. สร้างและเรียกใช้แอป แอปจะแสดง UI สําหรับส่วนย่อย SleepTrackerFragment แต่ไม่มีข้อมูล ปุ่มจะไม่ตอบสนองต่อการแตะ

ขั้นตอนที่ 2: ตรวจสอบแอปเริ่มต้น

  1. ดูไฟล์ Gradle
  • ไฟล์ Gradle โปรเจ็กต์
    ในไฟล์ build.gradle ระดับโปรเจ็กต์ ให้สังเกตตัวแปรที่ระบุเวอร์ชันของไลบรารี เวอร์ชันที่ใช้ในแอปเริ่มต้นทํางานร่วมกันได้ดีและทํางานร่วมกับแอปนี้ได้ดี เมื่อคุณดําเนินการ Codelab นี้เสร็จสิ้น Android Studio อาจแจ้งให้คุณอัปเดตบางเวอร์ชัน ทั้งนี้ขึ้นอยู่กับว่าคุณต้องการอัปเดตหรือใช้งานเวอร์ชันที่อยู่ในแอปต่อไป หากพบข้อผิดพลาดในการรวบรวม &&tt;strange" ให้ลองใช้ไลบรารีเวอร์ชันต่างๆ ที่แอปโซลูชันสุดท้ายใช้ร่วมกัน
  • ไฟล์ Gradle ของโมดูล ดูทรัพยากร Dependency ที่ระบุสําหรับไลบรารี Android Jetpack ทั้งหมด รวมถึง Room และทรัพยากร Dependency สําหรับ Coroutine
  1. ดูที่แพ็กเกจและ UI แอปมีโครงสร้างตามฟังก์ชันการทํางาน แพ็กเกจนี้มีไฟล์ตัวยึดตําแหน่งที่คุณจะเพิ่มโค้ดทั่วทั้ง Codelab ชุดนี้
  • แพ็กเกจ database สําหรับโค้ดทั้งหมดที่เกี่ยวข้องกับฐานข้อมูล Room
  • แพ็กเกจ sleepquality และ sleeptracker มีส่วนย่อย รูปแบบการดู และการดูโมเดลโรงงานสําหรับแต่ละหน้าจอ
  1. ดูที่ไฟล์ Util.kt ซึ่งมีฟังก์ชันที่จะช่วยแสดงข้อมูลคุณภาพการนอนหลับ โค้ดบางรายการได้รับการแสดงความคิดเห็นเนื่องจากอ้างอิงโมเดลข้อมูลพร็อพเพอร์ตี้ที่คุณสร้างในภายหลัง
  2. ดูโฟลเดอร์ androidTest (SleepDatabaseTest.kt) คุณจะใช้การทดสอบนี้เพื่อยืนยันว่าฐานข้อมูลทํางานตามที่ต้องการ

ใน Android ข้อมูลจะแสดงในคลาสข้อมูล และจะมีการเข้าถึงและแก้ไขข้อมูลโดยใช้การเรียกใช้ฟังก์ชัน แต่ในโลกฐานข้อมูล คุณต้องมีเอนทิตีและการค้นหา

  • เอนทิตีแสดงถึงออบเจ็กต์หรือแนวคิด ตลอดจนพร็อพเพอร์ตี้เพื่อจัดเก็บไว้ในฐานข้อมูล คลาสเอนทิตีจะระบุตาราง และแต่ละอินสแตนซ์ของคลาสนั้นแสดงถึงแถวในตาราง แต่ละพร็อพเพอร์ตี้จะกําหนดคอลัมน์ เอนทิตีนี้จะคงข้อมูลเกี่ยวกับการนอนหลับตอนกลางคืนไว้ในแอป
  • คําค้นหาคือคําขอข้อมูลจากตารางฐานข้อมูลหรือชุดค่าผสมของตาราง หรือคําขอดําเนินการกับข้อมูล คําถามที่พบบ่อยคือการรับ แทรก และอัปเดตเอนทิตี เช่น คุณอาจค้นหาจํานวนคืนการนอนหลับทั้งหมดที่บันทึกแล้ว โดยจัดเรียงตามเวลาเริ่มต้น

Room ทํางานอย่างเต็มที่เพื่อให้คุณได้รับจากคลาสข้อมูล Kotlin ไปยังเอนทิตีที่จัดเก็บในตาราง SQLite และจากการประกาศฟังก์ชันไปยังการค้นหา SQL

คุณต้องกําหนดเอนทิตีแต่ละรายการเป็นคลาสข้อมูลเสริม และการโต้ตอบเป็นอินเทอร์เฟซที่มีคําอธิบายประกอบ ออบเจ็กต์การเข้าถึงข้อมูล (DAO) Room ใช้คลาสที่มีคําอธิบายประกอบเหล่านี้เพื่อสร้างตารางในฐานข้อมูล และคําค้นหาที่ดําเนินการในฐานข้อมูล

ขั้นตอนที่ 1: สร้างเอนทิตี SleepNight

ในงานนี้ คุณจะกําหนดการนอนหลับ 1 คืนเป็นคลาสคําอธิบายประกอบ

สําหรับการนอนหลับ 1 คืน คุณจะต้องบันทึกเวลาเริ่มต้น เวลาสิ้นสุด และคะแนนคุณภาพ

และคุณต้องใช้รหัสเพื่อระบุจํานวนคืนที่ไม่ซ้ํากัน

  1. ในแพ็กเกจ database ให้ค้นหาและเปิดไฟล์ SleepNight.kt
  2. สร้างคลาสข้อมูล SleepNight ด้วยพารามิเตอร์สําหรับรหัส, เวลาเริ่มต้น (หน่วยเป็นมิลลิวินาที), เวลาสิ้นสุด (หน่วยเป็นมิลลิวินาที) และการให้คะแนนคุณภาพการนอนหลับที่เป็นตัวเลข
  • คุณต้องกําหนดค่า sleepQuality ให้เป็นค่าเริ่มต้น ดังนั้นให้ตั้งค่าเป็น -1 เพื่อระบุว่าไม่มีการรวบรวมข้อมูลคุณภาพ
  • และคุณยังต้องเริ่มต้นเวลาสิ้นสุดด้วย ตั้งเวลาเริ่มต้นเพื่อส่งสัญญาณแจ้งว่ายังไม่มีการบันทึกเวลาสิ้นสุด
data class SleepNight(
       var nightId: Long = 0L,
       val startTimeMilli: Long = System.currentTimeMillis(),
       var endTimeMilli: Long = startTimeMilli,
       var sleepQuality: Int = -1
)
  1. ก่อนที่จะประกาศชั้นเรียน ให้ใส่คําอธิบายประกอบ @Entity ในคลาสข้อมูล ตั้งชื่อตาราง daily_sleep_quality_table ไม่จําเป็นต้องใส่อาร์กิวเมนต์สําหรับ tableName แต่เราขอแนะนําให้ระบุ โดยคุณจะค้นหาอาร์กิวเมนต์อื่นๆ ได้ในเอกสารประกอบ

    หากได้รับข้อความแจ้ง ให้นําเข้า Entity และคําอธิบายประกอบอื่นๆ ทั้งหมดจากไลบรารี androidx
@Entity(tableName = "daily_sleep_quality_table")
data class SleepNight(...)
  1. หากต้องการระบุ nightId เป็นคีย์หลัก ให้อธิบายพร็อพเพอร์ตี้ nightId ด้วย @PrimaryKey ตั้งค่าพารามิเตอร์ autoGenerate เป็น true เพื่อให้ Room สร้างรหัสสําหรับแต่ละเอนทิตี ซึ่งจะรับประกันไม่ได้ว่ารหัสในแต่ละคืนจะเป็นรหัสที่ไม่ซ้ํากัน
@PrimaryKey(autoGenerate = true)
var nightId: Long = 0L,...
  1. เพิ่มคําอธิบายประกอบสําหรับที่พักที่เหลือด้วย @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
)
  1. สร้างและเรียกใช้โค้ดเพื่อให้มั่นใจว่าไม่มีข้อผิดพลาด

ในงานนี้ คุณจะได้ระบุออบเจ็กต์การเข้าถึงข้อมูล (DAO) DAO นําเสนอวิธีที่สะดวกสําหรับการแทรก ลบ และอัปเดตฐานข้อมูลใน Android

เมื่อใช้ฐานข้อมูล Room คุณจะค้นหาฐานข้อมูลได้โดยกําหนดและเรียกใช้ฟังก์ชัน Kotlin ในโค้ด ฟังก์ชัน Kotlin เหล่านี้จะแมปกับคําค้นหา SQL คุณกําหนดการแมปเหล่านั้นใน DAO โดยใช้คําอธิบายประกอบ และ Room จะสร้างโค้ดที่จําเป็น

ลองคิดว่า DAO คือการกําหนดอินเทอร์เฟซที่กําหนดเองสําหรับการเข้าถึงฐานข้อมูลของคุณ

สําหรับการดําเนินการฐานข้อมูลทั่วไป ไลบรารี Room จะมีคําอธิบายประกอบความสะดวก เช่น @Insert, @Delete และ @Update สําหรับสิ่งอื่นๆ ทั้งหมดจะมีคําอธิบายประกอบ @Query คุณเขียนคําค้นหาที่ SQLite รองรับได้

นอกจากนี้ คอมไพเลอร์จะตรวจสอบการค้นหา SQL เพื่อหาข้อผิดพลาดทางไวยากรณ์และเป็นโบนัสเพิ่มเติมเมื่อสร้างคําค้นหาใน Android Studio

คุณต้องดําเนินการต่อไปนี้ในฐานข้อมูลเครื่องมือติดตามการนอนหลับของคืน

  • แทรกคืนใหม่
  • อัปเดตคืนที่มีอยู่เพื่ออัปเดตเวลาสิ้นสุดและคะแนนคุณภาพ
  • รับคืนที่เฉพาะเจาะจงตามคีย์ของสถานที่นั้น
  • รับคืนทั้งหมดเพื่อให้คุณแสดงได้
  • ดูข้อมูลเมื่อคืนล่าสุด
  • ลบรายการทั้งหมดในฐานข้อมูล

ขั้นตอนที่ 1: สร้าง SleepDatabase DAO

  1. ในแพ็กเกจ database ให้เปิด SleepDatabaseDao.kt
  2. โปรดสังเกตว่า interface SleepDatabaseDao มีคําอธิบายประกอบ @Dao DAO ทั้งหมดต้องมีคําอธิบายประกอบด้วยคีย์เวิร์ด @Dao
@Dao
interface SleepDatabaseDao {}
  1. ในเนื้อหาของอินเทอร์เฟซ ให้เพิ่มคําอธิบายประกอบ @Insert ใต้ @Insert ให้เพิ่มฟังก์ชัน insert() ที่มีอินสแตนซ์ของคลาส Entity SleepNight เป็นอาร์กิวเมนต์

    เท่านี้ก็เรียบร้อย Room จะสร้างโค้ดที่จําเป็นทั้งหมดเพื่อแทรก SleepNight ลงในฐานข้อมูล เมื่อเรียกใช้ insert() จากโค้ด Kotlin Room จะเรียกใช้การค้นหา SQL เพื่อแทรกเอนทิตีลงในฐานข้อมูล (หมายเหตุ: คุณจะเรียกฟังก์ชันใดก็ได้ตามต้องการ)
@Insert
fun insert(night: SleepNight)
  1. เพิ่มคําอธิบายประกอบ @Update ที่มีฟังก์ชัน update() สําหรับ SleepNight รายการเดียว เอนทิตีที่อัปเดต # คือเอนทิตีที่มีคีย์เดียวกันกับคีย์ที่ส่ง คุณอัปเดตพร็อพเพอร์ตี้อื่นๆ บางส่วนหรือทั้งหมดได้
@Update
fun update(night: SleepNight)

ไม่มีคําอธิบายประกอบอํานวยความสะดวกสําหรับฟังก์ชันการทํางานที่เหลืออยู่ คุณจึงต้องใช้คําอธิบายประกอบ @Query และให้ข้อมูลการค้นหา SQLite

  1. เพิ่มคําอธิบายประกอบ @Query ด้วยฟังก์ชัน get() ที่ใช้อาร์กิวเมนต์ Long key และแสดงผล SleepNight เป็นค่าว่าง คุณจะเห็นข้อผิดพลาดสําหรับพารามิเตอร์ที่ขาดหายไป
@Query
fun get(key: Long): SleepNight?
  1. ระบบจะระบุคําค้นหาเป็นพารามิเตอร์สตริงไปยังคําอธิบายประกอบ เพิ่มพารามิเตอร์ใน @Query กําหนดเป็น String ที่เป็นคําค้นหา SQLite
  • เลือกคอลัมน์ทั้งหมดจาก daily_sleep_quality_table
  • WHERE nightId ตรงกับอาร์กิวเมนต์ :key

    ลองสังเกต :key คุณใช้เครื่องหมายทวิภาคในคําค้นหาเพื่ออ้างอิงอาร์กิวเมนต์ในฟังก์ชัน
("SELECT * from daily_sleep_quality_table WHERE nightId = :key")
  1. เพิ่ม @Query อีกรายการที่มีฟังก์ชัน clear() และการค้นหา SQL ไปยัง DELETE ทุกรายการจาก daily_sleep_quality_table การค้นหานี้จะไม่ลบตารางเอง

    คําอธิบายประกอบ @Delete จะลบ 1 รายการ แต่คุณใช้ @Delete และระบุรายการของคืนที่ต้องการลบได้ ข้อด้อยคือคุณจะต้องดึงข้อมูลหรือรู้สิ่งที่อยู่ในตาราง คําอธิบายประกอบ @Delete เหมาะสําหรับการลบรายการที่เจาะจง แต่ไม่เหมาะสําหรับการลบรายการทั้งหมดออกจากตาราง
@Query("DELETE FROM daily_sleep_quality_table")
fun clear()
  1. เพิ่ม @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?
  1. เพิ่ม @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>>
  1. แม้ว่าคุณจะไม่เห็นการเปลี่ยนแปลงที่มองเห็นได้ ให้เรียกใช้แอปเพื่อตรวจสอบว่าไม่มีข้อผิดพลาด

ในงานนี้ คุณจะได้สร้างฐานข้อมูล Room ที่ใช้ Entity และ DAO ที่สร้างไว้ในงานก่อนหน้า

คุณต้องสร้างคลาสผู้ถือฐานข้อมูลนามธรรมที่มีหมายเหตุ @Database คลาสนี้มี 1 วิธีสร้างอินสแตนซ์ของฐานข้อมูลได้หากไม่มีฐานข้อมูล หรือส่งคืนการอ้างอิงไปยังฐานข้อมูลที่มีอยู่

การรับฐานข้อมูล Room มีความเกี่ยวข้องเล็กน้อย ดังนั้นขั้นตอนทั่วไปก่อนที่จะเริ่มโค้ดมีดังนี้

  • สร้างชั้นเรียน public abstract ที่ extends RoomDatabase ชั้นเรียนนี้ เราจะทําหน้าที่เป็นผู้ถือฐานข้อมูล ชั้นเรียนนี้เป็นนามธรรมเนื่องจาก Room จะสร้างการใช้งานให้คุณ
  • เพิ่มหมายเหตุในชั้นเรียนด้วย @Database ในอาร์กิวเมนต์ ให้ประกาศเอนทิตีสําหรับฐานข้อมูลและกําหนดหมายเลขเวอร์ชัน
  • ภายในออบเจ็กต์ companion ให้กําหนดเมธอดนามธรรมหรือพร็อพเพอร์ตี้ที่ส่งคืน SleepDatabaseDao Room จะสร้างเนื้อหาให้คุณ
  • คุณต้องใช้ฐานข้อมูล Room เพียง 1 รายการสําหรับทั้งแอป ดังนั้นให้ใช้ RoomDatabase เป็นรายการเดียว
  • ใช้เครื่องมือสร้างฐานข้อมูลของ Room' เพื่อสร้างฐานข้อมูลเฉพาะในกรณีที่ไม่มีฐานข้อมูลอยู่ หรือส่งคืนฐานข้อมูลที่มีอยู่

ขั้นตอนที่ 1: สร้างฐานข้อมูล

  1. ในแพ็กเกจ database ให้เปิด SleepDatabase.kt
  2. ในไฟล์ ให้สร้างชั้นเรียน abstract ที่ชื่อว่า SleepDatabase เพื่อขยาย RoomDatabase

    เพิ่มหมายเหตุของชั้นเรียนด้วย @Database
@Database()
abstract class SleepDatabase : RoomDatabase() {}
  1. คุณจะเห็นข้อผิดพลาดเกี่ยวกับเอนทิตีและพารามิเตอร์เวอร์ชันที่ขาดหายไป คําอธิบายประกอบ @Database ต้องมีอาร์กิวเมนต์หลายรายการ เพื่อให้ Room สร้างฐานข้อมูลได้
  • ระบุ SleepNight เป็นสินค้ารายการเดียวที่มีรายชื่อ entities
  • ตั้งค่า version เป็น 1 ทุกครั้งที่เปลี่ยนสคีมา คุณจะต้องเพิ่มหมายเลขเวอร์ชัน
  • ตั้งค่า exportSchema เป็น false เพื่อไม่ให้ระบบสํารองข้อมูลประวัติเวอร์ชันสคีมา
entities = [SleepNight::class], version = 1, exportSchema = false
  1. ฐานข้อมูลต้องทราบเกี่ยวกับ DAO ภายในส่วนของชั้นเรียน ให้ประกาศค่านามธรรมที่แสดงผล SleepDatabaseDao คุณมี DAO ได้หลายรายการ
abstract val sleepDatabaseDao: SleepDatabaseDao
  1. ด้านล่าง ให้กําหนดออบเจ็กต์ companion ออบเจ็กต์ที่ใช้ร่วมกันจะช่วยให้ไคลเอ็นต์เข้าถึงวิธีสร้างหรือรับฐานข้อมูลโดยไม่ต้องเรียกใช้คลาสทันที เนื่องจากวัตถุประสงค์เดียวของคลาสนี้คือการระบุฐานข้อมูล จึงไม่มีเหตุผลที่ต้องเรียกใช้ฐานข้อมูลนี้
 companion object {}
  1. ในออบเจ็กต์ companion ให้ประกาศตัวแปรส่วนตัวที่ไม่มีข้อมูล INSTANCE สําหรับฐานข้อมูลและเริ่มต้นตัวแปรเป็น null ตัวแปร INSTANCE จะเก็บการอ้างอิงไปยังฐานข้อมูลเมื่อสร้างขึ้นแล้ว ซึ่งจะช่วยให้คุณไม่ต้องเปิดการเชื่อมต่อฐานข้อมูลบ่อยๆ ซึ่งมีค่าใช้จ่ายสูง

เพิ่มคําอธิบายประกอบ INSTANCE ด้วย @Volatile ค่าของตัวแปรผันผวนจะไม่ถูกแคช และการเขียนและการอ่านทั้งหมดจะดําเนินการจากและไปยังหน่วยความจําหลัก การดําเนินการนี้จะช่วยให้ค่าของ INSTANCE เป็นปัจจุบันและเหมือนกันกับชุดข้อความการดําเนินการทั้งหมด ซึ่งหมายความว่าการเปลี่ยนแปลงที่ทําโดยชุดข้อความหนึ่งไปยัง INSTANCE จะปรากฏต่อชุดข้อความอื่นๆ ทั้งหมดทันที และคุณไม่มีสถานการณ์ที่เกิดขึ้น เช่น ชุดข้อความ 2 รายการอัปเดตเอนทิตีเดียวกันในแคช ซึ่งจะทําให้เกิดปัญหา

@Volatile
private var INSTANCE: SleepDatabase? = null
  1. ด้านล่าง INSTANCE ซึ่งยังอยู่ในออบเจ็กต์ companion ให้กําหนดเมธอด getInstance() ด้วยพารามิเตอร์ Context ที่เครื่องมือสร้างฐานข้อมูลจะต้องใช้ แสดงประเภท SleepDatabase คุณจะเห็นข้อผิดพลาดเนื่องจาก getInstance() ยังไม่ได้ส่งคืนอะไร
fun getInstance(context: Context): SleepDatabase {}
  1. ภายใน getInstance() ให้เพิ่มบล็อก synchronized{} ส่งผ่านใน this เพื่อให้คุณเข้าถึงบริบทได้

    ชุดข้อความหลายรายการอาจขออินสแตนซ์ฐานข้อมูลพร้อมกัน ซึ่งทําให้มีฐานข้อมูล 2 รายการแทนที่จะเป็นฐานข้อมูล 1 รายการ ปัญหานี้ไม่น่าจะเกิดขึ้นในแอปตัวอย่างนี้ แต่อาจเป็นไปได้สําหรับแอปที่ซับซ้อนขึ้น การรวมโค้ดเพื่อดึงฐานข้อมูลไปยัง synchronized หมายความว่าจะมีการดําเนินการชุดข้อความเพียง 1 ชุดต่อครั้งเท่านั้น จึงอาจทําให้ฐานข้อมูลเริ่มต้นได้เพียงครั้งเดียว
synchronized(this) {}
  1. ภายในค่าที่ซิงค์ ให้คัดลอกค่าปัจจุบันของ INSTANCE ไปยังตัวแปร instance ในเครื่อง การดําเนินการนี้จะใช้ประโยชน์จากสมาร์ทแคสต์ ซึ่งใช้ได้กับตัวแปรภายในเท่านั้น
var instance = INSTANCE
  1. ภายในบล็อก synchronized, return instance ที่ส่วนท้ายของบล็อก synchronized ไม่สนใจข้อผิดพลาดประเภทการคืนสินค้าที่ไม่ตรงกัน และจะไม่แสดงเป็นนัลเมื่อเสร็จสิ้น
return instance
  1. เหนือคําสั่ง return ให้เพิ่มคําสั่ง if เพื่อตรวจสอบว่า instance มีค่าเป็น Null หรือไม่ ซึ่งยังไม่มีฐานข้อมูล
if (instance == null) {}
  1. หาก instance คือ null ให้ใช้เครื่องมือสร้างฐานข้อมูลเพื่อรับฐานข้อมูล ในเนื้อหาของคําสั่ง if ให้เรียกใช้ Room.databaseBuilder และระบุบริบทที่คุณส่งเข้ามา คลาสของฐานข้อมูล และชื่อสําหรับฐานข้อมูลชื่อ sleep_history_database หากต้องการนําข้อผิดพลาดออก คุณจะต้องเพิ่มกลยุทธ์การย้ายข้อมูลและ build() ในขั้นตอนต่อไปนี้
instance = Room.databaseBuilder(
                           context.applicationContext,
                           SleepDatabase::class.java,
                           "sleep_history_database")
  1. เพิ่มกลยุทธ์การย้ายข้อมูลที่จําเป็นลงในเครื่องมือสร้าง ใช้ .fallbackToDestructiveMigration()

    โดยปกติแล้ว คุณจะต้องระบุออบเจ็กต์การย้ายข้อมูลด้วยกลยุทธ์การย้ายข้อมูลเมื่อสคีมามีการเปลี่ยนแปลง ออบเจ็กต์การย้ายข้อมูลเป็นออบเจ็กต์ที่กําหนดวิธีรับแถวทั้งหมดด้วยสคีมาเก่าและแปลงเป็นแถวในสคีมาใหม่เพื่อไม่ให้ข้อมูลสูญหาย การย้ายข้อมูลอยู่นอกเหนือขอบเขตของ Codelab นี้ วิธีแก้ไขง่ายๆ คือการทําลายและสร้างฐานข้อมูลใหม่ ซึ่งหมายความว่าข้อมูลหาย
.fallbackToDestructiveMigration()
  1. และโทรหา .build()
.build()
  1. แล้วกําหนดให้ INSTANCE = instance เป็นขั้นตอนสุดท้ายภายในคําสั่ง if
INSTANCE = instance
  1. โค้ดสุดท้ายควรมีลักษณะดังนี้
@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
           }
       }
   }
}
  1. สร้างและเรียกใช้โค้ด

คุณมีองค์ประกอบทั้งหมดสําหรับการทํางานกับฐานข้อมูล Room แล้ว โค้ดนี้จะรวบรวมและเรียกใช้ แต่คุณไม่มีทางบอกได้ว่าโค้ดทํางานจริงหรือไม่ ตอนนี้จึงเป็นเวลาที่เหมาะสมในการเพิ่มการทดสอบพื้นฐาน

ขั้นตอนที่ 2: ทดสอบ SleepDatabase

ในขั้นตอนนี้ คุณจะเรียกใช้การทดสอบที่ให้ไว้เพื่อยืนยันว่าฐานข้อมูลทํางานได้ ซึ่งจะช่วยให้มั่นใจได้ว่าฐานข้อมูลจะทํางานได้ก่อนที่จะต่อยอด การทดสอบที่ให้ไว้เป็นข้อมูลเบื้องต้น สําหรับแอปเวอร์ชันที่ใช้งานจริง คุณจะใช้ฟังก์ชันและคําค้นหาทั้งหมดใน DAO ทั้งหมด

แอปเริ่มต้นมีโฟลเดอร์ androidTest โฟลเดอร์ androidTest นี้มีการทดสอบหน่วยที่เกี่ยวข้องกับการใช้เครื่องมือ Android ซึ่งเป็นวิธีที่ดีในการบอกว่าการทดสอบจะต้องใช้เฟรมเวิร์ก Android คุณจึงต้องเรียกใช้การทดสอบบนอุปกรณ์จริงหรืออุปกรณ์เสมือน แน่นอนว่าคุณสามารถสร้างและทําการทดสอบหน่วยล้วนๆ ซึ่งไม่เกี่ยวข้องกับเฟรมเวิร์ก Android ได้

  1. เปิดไฟล์ SleepDatabaseTest ใน Android Studio ในโฟลเดอร์ androidTest
  2. หากต้องการเลิกซ่อนโค้ด ให้เลือกโค้ดที่แสดงความคิดเห็นทั้งหมดแล้วกดแป้นพิมพ์ลัด Cmd+/ หรือ Control+/
  3. ตรวจดูไฟล์

ต่อไปนี้เป็นโค้ดการทดสอบแบบคร่าวๆ เพราะโค้ดอีกชิ้นหนึ่งที่คุณนํามาใช้ซ้ําได้มีดังนี้

  • SleepDabaseTest เป็นชั้นเรียนทดสอบ
  • คําอธิบายประกอบ @RunWith จะระบุตัวดําเนินการทดสอบ ซึ่งเป็นโปรแกรมที่กําหนดและทําการทดสอบ
  • ระหว่างการตั้งค่า ฟังก์ชันที่มีคําอธิบายประกอบเป็น @Before จะดําเนินการและสร้าง SleepDatabase ในหน่วยความจําด้วย SleepDatabaseDao "ในหน่วยความจํา"หมายความว่าฐานข้อมูลนี้จะไม่บันทึกไว้ในระบบไฟล์และจะถูกลบออกหลังจากการทดสอบทํางาน
  • และเมื่อสร้างฐานข้อมูลในหน่วยความจํา โค้ดจะเรียกใช้เมธอดทดสอบเฉพาะอีกอย่าง นั่นคือ allowMainThreadQueries โดยค่าเริ่มต้น ระบบจะแสดงข้อผิดพลาดหากคุณพยายามเรียกใช้คําค้นหาในชุดข้อความหลัก วิธีนี้จะช่วยให้คุณเรียกใช้การทดสอบในชุดข้อความหลักได้ ซึ่งทําได้เฉพาะเมื่อทดสอบ
  • ในการสร้างวิธีทดสอบที่มีคําอธิบายประกอบกับ @Test คุณจะสร้าง แทรก และเรียกข้อมูล SleepNight แล้วยืนยันได้ว่าเป็นวิธีเดียวกัน หากมีข้อผิดพลาดเกิดขึ้น ให้มีข้อยกเว้น ในการทดสอบจริง คุณจะมี @Test วิธีหลายวิธี
  • เมื่อทดสอบเสร็จแล้ว ฟังก์ชันที่มีคําอธิบายประกอบกับ @After จะสั่งปิดฐานข้อมูล
  1. คลิกขวาที่ไฟล์ทดสอบในแผงโปรเจ็กต์ แล้วเลือกเรียกใช้ 'SleepDatabaseTest'
  2. หลังจากทําการทดสอบแล้ว ให้ยืนยันในแผง 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:

เอกสารและบทความอื่นๆ

ส่วนนี้จะอธิบายการบ้านและรายงานสําหรับนักเรียนที่ทํางานผ่าน 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

เริ่มบทเรียนถัดไป: 6.2 Coroutine และ Room

สําหรับลิงก์ไปยัง Codelab อื่นๆ ในหลักสูตรนี้ โปรดดูหน้า Landing Page ของ Codelab ของ Android Kotlin Fundamentals