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

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

ข้อมูลเบื้องต้น

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

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

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

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

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

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

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

สิ่งที่คุณจะทํา

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

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

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

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

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

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

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

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

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

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 แล้ว และกลับไปอีกครั้ง อย่างไรก็ตาม เครื่องจัดการการคลิกที่ใช้การนําทางจากส่วนย่อยหนึ่งไปยังหน้าถัดไปยังไม่ได้เขียนโค้ด คุณเพิ่มรหัสดังกล่าวได้ใน ViewModel แล้ว

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

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

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

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

  1. ในแพ็กเกจ sleepquality ให้สร้างหรือเปิด SleepคุณภาพViewModel.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. สร้างเครื่องจัดการแบบคลิกครั้งเดียว onSetSleepQuality() เพื่อใช้รูปภาพที่มีคุณภาพในการนอนหลับทั้งหมด

    ใช้รูปแบบ Coroutine เดียวกันกับ Codelab ก่อนหน้า ดังนี้
  • เปิดตัว Coroutine ใน 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 ดังที่แสดงด้านล่าง ชั้นเรียนนี้ใช้โค้ด Boilerplate แบบเดียวกับที่คุณเคยเห็นมาก่อน ตรวจสอบโค้ดก่อนดําเนินการต่อ
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: อัปเดตโหมดสลีปการนอนหลับ

  1. เปิด SleepQualityFragment.kt
  2. ใน onCreateView() หลังจากได้รับ application คุณต้องได้รับ arguments ที่มาพร้อมกับการนําทาง อาร์กิวเมนต์เหล่านี้อยู่ใน SleepQualityFragmentArgs คุณต้องแตกไฟล์ออกจากแพ็กเกจ
val arguments = SleepQualityFragmentArgs.fromBundle(arguments!!)
  1. ถัดไป ให้ไปที่ dataSource
val dataSource = SleepDatabase.getInstance(application).sleepDatabaseDao
  1. สร้างโรงงานโดยผ่านใน 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 เพิ่มตัวแปรสําหรับ SleepQualityViewModel ในบล็อก <data>
 <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 ที่สมบูรณ์โดยใช้ Coroutine

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

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

ขั้นตอนที่ 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 สแน็คบาร์จะให้ความคิดเห็นสั้นๆ เกี่ยวกับการดําเนินการผ่านข้อความที่ด้านล่างของหน้าจอ สแน็กบาร์จะหายไปหลังจากหมดเวลา หรือหลังจากผู้ใช้สแน็กบาร์เลื่อนหน้าจอออกจากหน้าจอ

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

  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. แสดงสแน็คบาร์และรีเซ็ตเหตุการณ์ภายในบล็อกผู้สังเกตการณ์
   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: TrackMySleepคุณภาพFinal

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

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

การเริ่มการนําทาง

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

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

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

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

จุดอื่นๆ ที่ครอบคลุมใน Codelab นี้

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

หลักสูตร Udacity:

เอกสารประกอบสําหรับนักพัฒนาซอฟต์แวร์ Android

ส่วนนี้จะอธิบายการบ้านและรายงานสําหรับนักเรียนที่ทํางานผ่าน Codelab นี้ซึ่งเป็นส่วนหนึ่งของหลักสูตรที่นําโดยผู้สอน สิ่งที่ผู้สอนต้องทํามีดังนี้

  • มอบหมายการบ้านหากจําเป็น
  • สื่อสารกับนักเรียนเกี่ยวกับวิธีส่งงานทําการบ้าน
  • ตัดเกรดการบ้าน

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

หากคุณใช้ Codelab ด้วยตัวเอง ก็ให้ใช้การบ้านเพื่อทดสอบความรู้ของคุณได้

ตอบคําถามเหล่านี้

คำถามที่ 1

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

ขั้นตอนการใช้ค่า LiveData ที่เรียกว่า gotoBlueFragment เพื่อทริกเกอร์การนําทางจากส่วนย่อยสีแดงไปยังส่วนย่อยสีน้ําเงินมีอะไรบ้าง เลือกได้มากกว่า 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 ให้เพิ่มการสังเกตการณ์ไปยังแอตทริบิวต์ 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 Fundamentals