หลักพื้นฐานของ Android Kotlin 06.3: ใช้ LiveData เพื่อควบคุมสถานะปุ่ม

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

บทนำ

Codelab นี้จะสรุปวิธีใช้ ViewModel และ Fragment ร่วมกันเพื่อติดตั้งใช้งานการนำทาง โปรดทราบว่าเป้าหมายคือการใส่ตรรกะของเมื่อเพื่อไปยังส่วนต่างๆ ใน ViewModel แต่ให้กำหนดเส้นทางใน Fragment และไฟล์การนำทาง คุณใช้โมเดลมุมมอง Fragment LiveData และ Observer เพื่อให้บรรลุเป้าหมายนี้

Codelab จบลงด้วยการแสดงวิธีที่ชาญฉลาดในการติดตามสถานะปุ่มด้วยโค้ดที่น้อยที่สุด เพื่อให้แต่ละปุ่มเปิดใช้และคลิกได้เฉพาะเมื่อผู้ใช้ควรแตะปุ่มนั้น

สิ่งที่คุณควรทราบอยู่แล้ว

คุณควรคุ้นเคยกับสิ่งต่อไปนี้

  • การสร้างอินเทอร์เฟซผู้ใช้ (UI) พื้นฐานโดยใช้กิจกรรม Fragment และมุมมอง
  • การไปยังส่วนย่อยต่างๆ และการใช้ safeArgs เพื่อส่งข้อมูลระหว่างส่วนย่อย
  • ดูโมเดล โรงงานโมเดล การแปลง และ LiveData รวมถึง Observer ของโมเดล
  • วิธีสร้างRoomฐานข้อมูล สร้างออบเจ็กต์การเข้าถึงข้อมูล (DAO) และกำหนดเอนทิตี
  • วิธีใช้โครูทีนสำหรับการโต้ตอบกับฐานข้อมูลและงานอื่นๆ ที่ใช้เวลานาน

สิ่งที่คุณจะได้เรียนรู้

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

สิ่งที่คุณต้องดำเนินการ

  • ขยายแอป TrackMySleepQuality เพื่อรวบรวมคะแนนคุณภาพ เพิ่มคะแนนลงในฐานข้อมูล และแสดงผลลัพธ์
  • ใช้ LiveData เพื่อทริกเกอร์การแสดงแถบแสดงข้อความ
  • ใช้ LiveData เพื่อเปิดและปิดใช้ปุ่ม

ใน Codelab นี้ คุณจะได้สร้างการบันทึกคุณภาพการนอนหลับและ UI สุดท้ายของแอป TrackMySleepQuality

แอปมี 2 หน้าจอซึ่งแสดงด้วย Fragment ดังที่แสดงในรูปภาพด้านล่าง

หน้าจอแรกที่แสดงทางด้านซ้ายมีปุ่มสำหรับเริ่มและหยุดการติดตาม หน้าจอจะแสดงข้อมูลการนอนหลับทั้งหมดของผู้ใช้ ปุ่มล้างจะลบข้อมูลทั้งหมดที่แอปเก็บรวบรวมไว้สำหรับผู้ใช้ออกอย่างถาวร

หน้าจอที่ 2 ซึ่งแสดงทางด้านขวาใช้สำหรับเลือกคะแนนคุณภาพการนอนหลับ ในแอป การจัดประเภทจะแสดงเป็นตัวเลข แอปจะแสดงทั้งไอคอนใบหน้าและค่าเทียบเท่าที่เป็นตัวเลขเพื่อวัตถุประสงค์ในการพัฒนา

โฟลว์ของผู้ใช้มีดังนี้

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

แอปนี้ใช้สถาปัตยกรรมที่เรียบง่าย ดังที่แสดงด้านล่างในบริบทของสถาปัตยกรรมแบบเต็ม แอปใช้เฉพาะคอมโพเนนต์ต่อไปนี้

  • ตัวควบคุม UI
  • ดูโมเดลและ LiveData
  • ฐานข้อมูล Room

Codelab นี้ถือว่าคุณรู้วิธีใช้การนำทางโดยใช้ Fragment และไฟล์การนำทาง เราได้จัดเตรียมโค้ดส่วนใหญ่ไว้ให้คุณแล้วเพื่อช่วยประหยัดเวลา

ขั้นตอนที่ 1: ตรวจสอบโค้ด

  1. หากต้องการเริ่มต้น ให้ใช้โค้ดของคุณเองจากตอนท้ายของ Codelab สุดท้าย หรือดาวน์โหลดโค้ดเริ่มต้น
  2. ในโค้ดเริ่มต้น ให้ตรวจสอบ SleepQualityFragment คลาสนี้จะขยายเลย์เอาต์ รับแอปพลิเคชัน และส่งคืน binding.root
  3. เปิด navigation.xml ในตัวแก้ไขดีไซน์ คุณจะเห็นเส้นทางการนำทางจาก SleepTrackerFragment ไปยัง SleepQualityFragment และกลับจาก SleepQualityFragment ไปยัง SleepTrackerFragment



  4. ตรวจสอบโค้ดสำหรับ navigation.xml โดยเฉพาะอย่างยิ่ง ให้มองหา <argument> ที่ชื่อ sleepNightKey

    เมื่อผู้ใช้เปลี่ยนจากSleepTrackerFragmentเป็นSleepQualityFragment, แอปจะส่งsleepNightKeyไปยังSleepQualityFragmentสำหรับคืนที่ต้องอัปเดต

ขั้นตอนที่ 2: เพิ่มการนำทางสำหรับการติดตามคุณภาพการนอนหลับ

กราฟการนำทางมีเส้นทางจาก SleepTrackerFragment ไปยัง SleepQualityFragment และกลับมาอีกครั้งอยู่แล้ว อย่างไรก็ตาม เรายังไม่ได้เขียนโค้ดตัวแฮนเดิลคลิกที่ใช้การนำทางจาก Fragment หนึ่งไปยัง Fragment ถัดไป คุณเพิ่มโค้ดนั้นใน ViewModel ได้เลย

ในตัวแฮนเดิลการคลิก คุณจะตั้งค่า LiveData ที่เปลี่ยนเมื่อต้องการให้แอปไปยังปลายทางอื่น Fragment จะสังเกต LiveData นี้ เมื่อข้อมูลเปลี่ยนแปลง Fragment จะไปยังปลายทางและบอก ViewModel ว่าดำเนินการเสร็จแล้ว ซึ่งจะรีเซ็ตตัวแปรสถานะ

  1. เปิด SleepTrackerViewModel คุณต้องเพิ่มการนำทางเพื่อให้เมื่อผู้ใช้แตะปุ่มหยุด แอปจะนำทางไปยัง SleepQualityFragment เพื่อรวบรวมคะแนนคุณภาพ
  2. ใน SleepTrackerViewModel ให้สร้าง LiveData ที่เปลี่ยนเมื่อคุณต้องการให้แอปไปยัง SleepQualityFragment ใช้การห่อหุ้มเพื่อแสดงเฉพาะเวอร์ชันที่รับได้ของ LiveData ต่อ ViewModel

    คุณวางโค้ดนี้ไว้ที่ใดก็ได้ในระดับบนสุดของเนื้อหาในชั้นเรียน
private val _navigateToSleepQuality = MutableLiveData<SleepNight>()

val navigateToSleepQuality: LiveData<SleepNight>
   get() = _navigateToSleepQuality
  1. เพิ่มdoneNavigating()ฟังก์ชันที่รีเซ็ตตัวแปรที่ทริกเกอร์การนำทาง
fun doneNavigating() {
   _navigateToSleepQuality.value = null
}
  1. ในตัวแฮนเดิลการคลิกสำหรับปุ่มหยุด onStopTracking() ให้ทริกเกอร์การนำทางไปยัง SleepQualityFragment ตั้งค่าตัวแปร _navigateToSleepQuality ที่ส่วนท้ายของฟังก์ชันเป็นรายการสุดท้ายภายในบล็อก launch{} โปรดทราบว่าตัวแปรนี้ตั้งค่าเป็น night เมื่อตัวแปรนี้มีค่า แอปจะไปยัง SleepQualityFragment พร้อมส่งต่อระยะเวลาที่ค้างคืน
_navigateToSleepQuality.value = oldNight
  1. SleepTrackerFragment ต้องสังเกต _navigateToSleepQuality เพื่อให้แอปทราบเวลาที่ควรไปยังส่วนต่างๆ ใน SleepTrackerFragment ใน onCreateView() ให้เพิ่มผู้สังเกตการณ์สำหรับ navigateToSleepQuality() โปรดทราบว่าการนำเข้าสำหรับรายการนี้ไม่ชัดเจนและคุณต้องนำเข้า androidx.lifecycle.Observer
sleepTrackerViewModel.navigateToSleepQuality.observe(this, Observer {
})

  1. ภายในบล็อก Observer ให้ไปที่และส่งรหัสของคืนปัจจุบัน จากนั้นเรียกใช้ doneNavigating() หากการนำเข้าไม่ชัดเจน ให้นำเข้า androidx.navigation.fragment.findNavController
night ->
night?.let {
   this.findNavController().navigate(
           SleepTrackerFragmentDirections
                   .actionSleepTrackerFragmentToSleepQualityFragment(night.nightId))
   sleepTrackerViewModel.doneNavigating()
}
  1. สร้างและเรียกใช้แอป แตะเริ่ม แล้วแตะหยุด ซึ่งจะนำคุณไปยังหน้าจอ SleepQualityFragment หากต้องการกลับ ให้ใช้ปุ่มย้อนกลับของระบบ

ในงานนี้ คุณจะบันทึกคุณภาพการนอนหลับและกลับไปที่ Fragment ของเครื่องมือติดตามการนอนหลับ จอแสดงผลควรอัปเดตโดยอัตโนมัติเพื่อแสดงค่าที่อัปเดตแล้วต่อผู้ใช้ คุณต้องสร้าง ViewModel และ ViewModelFactory รวมถึงอัปเดต SleepQualityFragment

ขั้นตอนที่ 1: สร้าง ViewModel และ ViewModelFactory

  1. ในsleepqualityแพ็กเกจ ให้สร้างหรือเปิด SleepQualityViewModel.kt
  2. สร้างคลาส SleepQualityViewModel ที่ใช้ sleepNightKey และฐานข้อมูลเป็นอาร์กิวเมนต์ คุณต้องส่ง database จากโรงงานเช่นเดียวกับที่ทำสำหรับ SleepTrackerViewModel นอกจากนี้ คุณยังต้องส่ง sleepNightKey จากการนำทางด้วย
class SleepQualityViewModel(
       private val sleepNightKey: Long = 0L,
       val database: SleepDatabaseDao) : ViewModel() {
}
  1. ภายในคลาส SleepQualityViewModel ให้กำหนด Job และ uiScope แล้วลบล้าง onCleared()
private val viewModelJob = Job()
private val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)

override fun onCleared() {
   super.onCleared()
   viewModelJob.cancel()
}
  1. หากต้องการกลับไปที่ SleepTrackerFragment โดยใช้รูปแบบเดียวกันกับด้านบน ให้ประกาศ _navigateToSleepTracker ใช้ navigateToSleepTracker และ doneNavigating()
private val _navigateToSleepTracker = MutableLiveData<Boolean?>()

val navigateToSleepTracker: LiveData<Boolean?>
   get() = _navigateToSleepTracker

fun doneNavigating() {
   _navigateToSleepTracker.value = null
}
  1. สร้างตัวแฮนเดิลการคลิก 1 รายการ onSetSleepQuality() สำหรับรูปภาพคุณภาพการนอนหลับทั้งหมดที่จะใช้

    ใช้รูปแบบโครูทีนเดียวกันกับในโค้ดแล็บก่อนหน้า
  • เปิดใช้โครูทีนใน uiScope แล้วเปลี่ยนไปใช้ตัวจัดสรร I/O
  • รับ tonight โดยใช้ sleepNightKey
  • ตั้งค่าคุณภาพการนอนหลับ
  • อัปเดตฐานข้อมูล
  • ทริกเกอร์การนำทาง

โปรดสังเกตว่าตัวอย่างโค้ดด้านล่างจะทำงานทั้งหมดในตัวแฮนเดิลการคลิก แทนที่จะแยกการดำเนินการฐานข้อมูลในบริบทต่างๆ

fun onSetSleepQuality(quality: Int) {
        uiScope.launch {
            // IO is a thread pool for running operations that access the disk, such as
            // our Room database.
            withContext(Dispatchers.IO) {
                val tonight = database.get(sleepNightKey) ?: return@withContext
                tonight.sleepQuality = quality
                database.update(tonight)
            }

            // Setting this state variable to true will alert the observer and trigger navigation.
            _navigateToSleepTracker.value = true
        }
    }
  1. ในแพ็กเกจ sleepquality ให้สร้างหรือเปิด SleepQualityViewModelFactory.kt แล้วเพิ่มคลาส SleepQualityViewModelFactory ดังที่แสดงด้านล่าง คลาสนี้ใช้โค้ดบอยเลอร์เพลตเวอร์ชันเดียวกับที่คุณเคยเห็น ตรวจสอบโค้ดก่อนดำเนินการต่อ
class SleepQualityViewModelFactory(
       private val sleepNightKey: Long,
       private val dataSource: SleepDatabaseDao) : ViewModelProvider.Factory {
   @Suppress("unchecked_cast")
   override fun <T : ViewModel?> create(modelClass: Class<T>): T {
       if (modelClass.isAssignableFrom(SleepQualityViewModel::class.java)) {
           return SleepQualityViewModel(sleepNightKey, dataSource) as T
       }
       throw IllegalArgumentException("Unknown ViewModel class")
   }
}

ขั้นตอนที่ 2: อัปเดต SleepQualityFragment

  1. เปิด SleepQualityFragment.kt
  2. ในonCreateView() หลังจากได้รับapplicationแล้ว คุณจะต้องรับargumentsที่มาพร้อมกับการนำทาง อาร์กิวเมนต์เหล่านี้อยู่ใน SleepQualityFragmentArgs คุณต้องแยกไฟล์เหล่านั้นออกจากแพ็กเกจ
val arguments = SleepQualityFragmentArgs.fromBundle(arguments!!)
  1. จากนั้นรับ dataSource
val dataSource = SleepDatabase.getInstance(application).sleepDatabaseDao
  1. สร้าง Factory โดยส่ง dataSource และ sleepNightKey
val viewModelFactory = SleepQualityViewModelFactory(arguments.sleepNightKey, dataSource)
  1. รับViewModelการอ้างอิง
val sleepQualityViewModel =
       ViewModelProviders.of(
               this, viewModelFactory).get(SleepQualityViewModel::class.java)
  1. เพิ่ม ViewModel ไปยังออบเจ็กต์การเชื่อมโยง (หากเห็นข้อผิดพลาดเกี่ยวกับออบเจ็กต์การเชื่อมโยง ให้ข้ามไปก่อน)
binding.sleepQualityViewModel = sleepQualityViewModel
  1. เพิ่มผู้สังเกตการณ์ เมื่อมีข้อความแจ้ง ให้นำเข้า androidx.lifecycle.Observer
sleepQualityViewModel.navigateToSleepTracker.observe(this, Observer {
   if (it == true) { // Observed state is true.
       this.findNavController().navigate(
               SleepQualityFragmentDirections.actionSleepQualityFragmentToSleepTrackerFragment())
       sleepQualityViewModel.doneNavigating()
   }
})

ขั้นตอนที่ 3: อัปเดตไฟล์เลย์เอาต์และเรียกใช้แอป

  1. เปิดไฟล์เลย์เอาต์ fragment_sleep_quality.xml ในบล็อก <data> ให้เพิ่มตัวแปรสำหรับ SleepQualityViewModel
 <data>
       <variable
           name="sleepQualityViewModel"
           type="com.example.android.trackmysleepquality.sleepquality.SleepQualityViewModel" />
   </data>
  1. สำหรับรูปภาพคุณภาพการนอนหลับทั้ง 6 รูป ให้เพิ่มตัวแฮนเดิลการคลิกเหมือนกับตัวแฮนเดิลด้านล่าง จับคู่คะแนนคุณภาพกับรูปภาพ
android:onClick="@{() -> sleepQualityViewModel.onSetSleepQuality(5)}"
  1. ล้างและสร้างโปรเจ็กต์ใหม่ ซึ่งจะช่วยแก้ไขข้อผิดพลาดเกี่ยวกับออบเจ็กต์การเชื่อมโยง ไม่เช่นนั้น ให้ล้างแคช (File > Invalidate Caches / Restart) แล้วสร้างแอปใหม่

ยินดีด้วย คุณเพิ่งสร้างแอปฐานข้อมูล Room ที่สมบูรณ์โดยใช้โครูทีน

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

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

ขั้นตอนที่ 1: อัปเดตสถานะปุ่ม

แนวคิดคือการตั้งค่าสถานะปุ่มเพื่อให้ในตอนแรกมีเพียงปุ่มเริ่มเท่านั้นที่เปิดใช้ ซึ่งหมายความว่าปุ่มนี้คลิกได้

หลังจากที่ผู้ใช้แตะเริ่มแล้ว ปุ่มหยุดจะเปิดใช้ได้ แต่ปุ่มเริ่มจะใช้ไม่ได้ ปุ่มล้างจะเปิดใช้เมื่อมีข้อมูลในฐานข้อมูลเท่านั้น

  1. เปิดไฟล์เลย์เอาต์ fragment_sleep_tracker.xml
  2. เพิ่มพร็อพเพอร์ตี้ android:enabled ลงในแต่ละปุ่ม พร็อพเพอร์ตี้ android:enabled เป็นค่าบูลีนที่ระบุว่าปุ่มเปิดใช้หรือไม่ (แตะปุ่มที่เปิดใช้ได้ แต่แตะปุ่มที่ปิดใช้ไม่ได้) กำหนดค่าพร็อพเพอร์ตี้เป็นค่าของตัวแปรสถานะที่คุณจะกำหนดในอีกสักครู่

start_button:

android:enabled="@{sleepTrackerViewModel.startButtonVisible}"

stop_button:

android:enabled="@{sleepTrackerViewModel.stopButtonVisible}"

clear_button:

android:enabled="@{sleepTrackerViewModel.clearButtonVisible}"
  1. เปิด SleepTrackerViewModel แล้วสร้างตัวแปรที่สอดคล้องกัน 3 รายการ กำหนดการเปลี่ยนรูปแบบที่ทดสอบตัวแปรแต่ละรายการ
  • ปุ่มเริ่มควรเปิดใช้เมื่อ tonight เป็น null
  • ควรเปิดใช้ปุ่มหยุดเมื่อ tonight ไม่ใช่ null
  • ปุ่มล้างควรเปิดใช้ก็ต่อเมื่อ nights และฐานข้อมูลมีคืนที่นอนหลับ
val startButtonVisible = Transformations.map(tonight) {
   it == null
}
val stopButtonVisible = Transformations.map(tonight) {
   it != null
}
val clearButtonVisible = Transformations.map(nights) {
   it?.isNotEmpty()
}
  1. เรียกใช้แอปและทดลองใช้ปุ่มต่างๆ

ขั้นตอนที่ 2: ใช้แถบแสดงข้อความเพื่อแจ้งให้ผู้ใช้ทราบ

หลังจากผู้ใช้ล้างฐานข้อมูลแล้ว ให้แสดงการยืนยันแก่ผู้ใช้โดยใช้วิดเจ็ต Snackbar แถบแสดงข้อความจะให้คำอธิบายสั้นๆ เกี่ยวกับการดำเนินการผ่านข้อความที่ด้านล่างของหน้าจอ แถบแสดงข้อความจะหายไปหลังจากหมดเวลา หลังจากที่ผู้ใช้โต้ตอบที่อื่นบนหน้าจอ หรือหลังจากที่ผู้ใช้ปัดแถบแสดงข้อความออกจากหน้าจอ

การแสดงแถบแสดงข้อความสั้นๆ เป็นงาน UI และควรเกิดขึ้นใน Fragment การตัดสินใจว่าจะแสดงแถบแสดงข้อความหรือไม่จะเกิดขึ้นใน ViewModel หากต้องการตั้งค่าและทริกเกอร์แถบแสดงข้อความเมื่อล้างข้อมูล คุณสามารถใช้เทคนิคเดียวกับการทริกเกอร์การนำทางได้

  1. สร้างเหตุการณ์ที่แคปซูลในSleepTrackerViewModel
private var _showSnackbarEvent = MutableLiveData<Boolean>()

val showSnackBarEvent: LiveData<Boolean>
   get() = _showSnackbarEvent
  1. จากนั้นให้ใช้ doneShowingSnackbar()
fun doneShowingSnackbar() {
   _showSnackbarEvent.value = false
}
  1. ใน SleepTrackerFragment ใน onCreateView() ให้เพิ่มผู้สังเกตการณ์
sleepTrackerViewModel.showSnackBarEvent.observe(this, Observer { })
  1. ภายในบล็อก Observer ให้แสดง Snackbar และรีเซ็ตเหตุการณ์ทันที
   if (it == true) { // Observed state is true.
       Snackbar.make(
               activity!!.findViewById(android.R.id.content),
               getString(R.string.cleared_message),
               Snackbar.LENGTH_SHORT // How long to display the message.
       ).show()
       sleepTrackerViewModel.doneShowingSnackbar()
   }
  1. ใน SleepTrackerViewModel ให้ทริกเกอร์เหตุการณ์ในเมธอด onClear() โดยกำหนดมูลค่าเหตุการณ์เป็น true ภายในบล็อก launch ดังนี้
_showSnackbarEvent.value = true
  1. สร้างและเรียกใช้แอป

โปรเจ็กต์ Android Studio: TrackMySleepQualityFinal

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

  • สร้างViewModelและViewModelFactory แล้วตั้งค่าแหล่งข้อมูล
  • ทริกเกอร์การนำทาง หากต้องการแยกความกังวล ให้วางตัวแฮนเดิลการคลิกใน ViewModel และการนำทางใน Fragment
  • ใช้การห่อหุ้มกับ LiveData เพื่อติดตามและตอบสนองต่อการเปลี่ยนแปลงสถานะ
  • ใช้การเปลี่ยนรูปแบบกับ LiveData
  • สร้างฐานข้อมูลแบบเดี่ยว
  • ตั้งค่าโครูทีนสำหรับการดำเนินการฐานข้อมูล

การทริกเกอร์การนำทาง

คุณกำหนดเส้นทางการนำทางที่เป็นไปได้ระหว่าง Fragment ในไฟล์การนำทาง การเรียกใช้การนำทางจาก Fragment หนึ่งไปยัง Fragment ถัดไปทำได้หลายวิธี ซึ่งได้แก่

  • กำหนดonClickตัวแฮนเดิลเพื่อทริกเกอร์การนำทางไปยัง Fragment ปลายทาง
  • หรือหากต้องการเปิดใช้การนำทางจาก Fragment หนึ่งไปยัง Fragment ถัดไป ให้ทำดังนี้
  • กําหนดค่า LiveData เพื่อบันทึกว่าควรมีการนําทางหรือไม่
  • แนบ Observer กับค่า LiveData นั้น
  • จากนั้นโค้ดจะเปลี่ยนค่าดังกล่าวเมื่อใดก็ตามที่ต้องทริกเกอร์การนำทางหรือการนำทางเสร็จสมบูรณ์

การตั้งค่าแอตทริบิวต์ android:enabled

  • แอตทริบิวต์ android:enabled มีการกำหนดไว้ใน TextView และคลาสย่อยทั้งหมดจะรับค่าแอตทริบิวต์นี้ รวมถึง Button
  • แอตทริบิวต์ android:enabled จะกำหนดว่าจะเปิดใช้ View หรือไม่ ความหมายของ "เปิดใช้" จะแตกต่างกันไปตามคลาสย่อย เช่น EditText ที่ไม่ได้เปิดใช้จะป้องกันไม่ให้ผู้ใช้แก้ไขข้อความที่อยู่ในนั้น และ Button ที่ไม่ได้เปิดใช้จะป้องกันไม่ให้ผู้ใช้แตะปุ่ม
  • แอตทริบิวต์ enabled ไม่เหมือนกับแอตทริบิวต์ visibility
  • คุณสามารถใช้แผนที่การเปลี่ยนรูปแบบเพื่อกำหนดค่าของแอตทริบิวต์ enabled ของปุ่มตามสถานะของออบเจ็กต์หรือตัวแปรอื่น

ประเด็นอื่นๆ ที่ครอบคลุมใน Codelab นี้มีดังนี้

  • หากต้องการทริกเกอร์การแจ้งเตือนให้ผู้ใช้ คุณสามารถใช้วิธีเดียวกับที่ใช้ทริกเกอร์การนำทาง
  • คุณใช้ Snackbar เพื่อแจ้งเตือนผู้ใช้ได้

หลักสูตร Udacity:

เอกสารประกอบสำหรับนักพัฒนาแอป Android

ส่วนนี้แสดงรายการการบ้านที่เป็นไปได้สำหรับนักเรียน/นักศึกษาที่กำลังทำ Codelab นี้เป็นส่วนหนึ่งของหลักสูตรที่สอนโดยผู้สอน ผู้สอนมีหน้าที่ดำเนินการต่อไปนี้

  • มอบหมายการบ้านหากจำเป็น
  • สื่อสารกับนักเรียนเกี่ยวกับวิธีส่งงานที่ได้รับมอบหมาย
  • ให้คะแนนงานการบ้าน

ผู้สอนสามารถใช้คำแนะนำเหล่านี้ได้มากน้อยตามที่ต้องการ และควรมีอิสระในการมอบหมายการบ้านอื่นๆ ที่เห็นว่าเหมาะสม

หากคุณกำลังทำ Codelab นี้ด้วยตนเอง โปรดใช้แบบฝึกหัดเหล่านี้เพื่อทดสอบความรู้ของคุณ

ตอบคำถามต่อไปนี้

คำถามที่ 1

วิธีหนึ่งในการเปิดใช้แอปเพื่อทริกเกอร์การนำทางจาก Fragment หนึ่งไปยังอีก Fragment คือการใช้ค่า LiveData เพื่อระบุว่าจะทริกเกอร์การนำทางหรือไม่

ขั้นตอนในการใช้ค่า LiveData ที่เรียกว่า gotoBlueFragment เพื่อทริกเกอร์การนำทางจาก Fragment สีแดงไปยัง Fragment สีน้ำเงินมีอะไรบ้าง โดยเลือกได้มากกว่า 1 ข้อ

  • ใน ViewModel ให้กำหนดค่า LiveData เป็น gotoBlueFragment
  • ใน RedFragment ให้สังเกตค่า gotoBlueFragment ใช้โค้ด observe{} เพื่อไปยัง BlueFragment เมื่อเหมาะสม จากนั้นรีเซ็ตค่าของ gotoBlueFragment เพื่อระบุว่าการนำทางเสร็จสมบูรณ์แล้ว
  • ตรวจสอบว่าโค้ดตั้งค่าตัวแปร gotoBlueFragment เป็นค่าที่ทริกเกอร์การนำทางทุกครั้งที่แอปต้องเปลี่ยนจาก RedFragment ไปยัง BlueFragment
  • ตรวจสอบว่าโค้ดของคุณกําหนดแฮนเดิล onClick สําหรับ View ที่ผู้ใช้คลิกเพื่อไปยัง BlueFragment ซึ่งแฮนเดิล onClick จะสังเกตค่า goToBlueFragment

คำถามที่ 2

คุณเปลี่ยนได้ว่าจะเปิดใช้ (คลิกได้) หรือไม่เปิดใช้ Button โดยใช้ LiveData คุณจะตรวจสอบว่าแอปเปลี่ยนปุ่ม UpdateNumber เพื่อให้มีลักษณะดังนี้ได้อย่างไร

  • ปุ่มจะเปิดใช้หาก myNumber มีค่ามากกว่า 5
  • ปุ่มจะปิดใช้อยู่หาก myNumber เท่ากับหรือน้อยกว่า 5

สมมติว่าเลย์เอาต์ที่มีปุ่ม UpdateNumber มีตัวแปร <data> สำหรับ NumbersViewModel ดังที่แสดงที่นี่

<data>
   <variable
       name="NumbersViewModel"
       type="com.example.android.numbersapp.NumbersViewModel" />
</data>

สมมติว่ารหัสของปุ่มในไฟล์เลย์เอาต์เป็นดังนี้

android:id="@+id/update_number_button"

สิ่งที่ต้องทำเพิ่มเติม เลือกได้มากกว่า 1 ข้อ

  • ในคลาส NumbersViewModel ให้กำหนดตัวแปร LiveData, myNumber ซึ่งแสดงถึงตัวเลข นอกจากนี้ ให้กำหนดตัวแปรที่มีค่าที่ตั้งค่าโดยการเรียก Transform.map() ในตัวแปร myNumber ซึ่งจะแสดงผลบูลีนที่ระบุว่าตัวเลขนั้นมากกว่า 5 หรือไม่

    กล่าวคือ ใน ViewModel ให้เพิ่มโค้ดต่อไปนี้
val myNumber: LiveData<Int>

val enableUpdateNumberButton = Transformations.map(myNumber) {
   myNumber > 5
}
  • ในเลย์เอาต์ XML ให้ตั้งค่าแอตทริบิวต์ android:enabled ของ update_number_button button เป็น NumberViewModel.enableUpdateNumbersButton
android:enabled="@{NumbersViewModel.enableUpdateNumberButton}"
  • ใน Fragment ที่ใช้คลาส NumbersViewModel ให้เพิ่ม Observer ลงในแอตทริบิวต์ enabled ของปุ่ม

    กล่าวคือ ใน Fragment ให้เพิ่มโค้ดต่อไปนี้
// Observer for the enabled attribute
viewModel.enabled.observe(this, Observer<Boolean> { isEnabled ->
   myNumber > 5
})
  • ในไฟล์เลย์เอาต์ ให้ตั้งค่าแอตทริบิวต์ android:enabled ของ update_number_button button เป็น "Observable"

ไปที่บทเรียนถัดไป: 7.1 พื้นฐานของ RecyclerView

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