คู่มือฉบับสมบูรณ์เกี่ยวกับ StateFlow และ SharedFlow: ประสิทธิภาพเหนือกว่า LiveData บน Android

  • ความแตกต่างพื้นฐานระหว่างโฟลว์เย็น (Flow) และโฟลว์ร้อน (StateFlow และ SharedFlow) สำหรับการจัดการข้อมูล
  • เกณฑ์ในการเลือกใช้ระหว่าง StateFlow สำหรับสถานะถาวรและ SharedFlow สำหรับเหตุการณ์ชั่วคราว
  • กลยุทธ์การรวบรวมข้อมูลที่ปลอดภัยโดยใช้ repeatOnLifecycle เพื่อเพิ่มประสิทธิภาพการใช้ทรัพยากรในส่วนติดต่อผู้ใช้ (UI)

StateFlow และ SharedFlow: ประสิทธิภาพเหนือกว่า LiveData บน Android

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

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

แนวคิดเรื่องการไหลเวียน: เย็นหรือร้อน?

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

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

StateFlow: ตัวเลือกที่เหมาะสมที่สุดในการทดแทน LiveData

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

การกำหนดค่าและโครงสร้างของโปรเจ็กต์แบบหลายโมดูลใน Android Studio
บทความที่เกี่ยวข้อง:
คู่มือฉบับสมบูรณ์สำหรับการตั้งค่าและการจัดโครงสร้างโปรเจ็กต์แบบหลายโมดูลใน Android Studio

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

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

SharedFlow: ตัวกลางรับส่งข้อมูลเหตุการณ์สำหรับการกระทำเฉพาะต่างๆ

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

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

การเปรียบเทียบทางเทคนิค: StateFlow เทียบกับ SharedFlow เทียบกับ LiveData

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

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

ความสำคัญของการเก็บเกี่ยวอย่างปลอดภัย

ข้อผิดพลาดที่พบบ่อยมากคือการเรียกใช้คำสั่ง `collect` ภายในขอบเขตของ coroutine แบบง่ายๆ ใน Activity ซึ่งเป็นอันตรายเพราะกระบวนการทำงานจะยังคงประมวลผลข้อมูลต่อไปแม้ว่าแอปจะทำงานอยู่เบื้องหลังซึ่งอาจทำให้แอปหยุดทำงานหรือใช้ CPU มากเกินไป วิธีแก้ปัญหาที่ทันสมัยคือการใช้ API `repeatOnLifecycle(Lifecycle.State.STARTED) `

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

เปลี่ยนกระแสเย็นให้เป็นกระแสร้อน

บางครั้งเรามีโฟลว์ที่มาจากฐานข้อมูล (เช่น Room) หรือแหล่งเก็บข้อมูล และโฟลว์นั้นยังไม่ได้เปิดใช้งาน เพื่อให้โฟลว์นั้นเปิดใช้งานได้ เราจะใช้ ตัวดำเนินการ `stateIn` หรือ `shareIn`ตัวดำเนินการเหล่านี้ต้องการ `CoroutineScope` และกลยุทธ์การเริ่มต้น กลยุทธ์ที่ใช้กันมากที่สุดคือ`SharingStarted.WhileSubscribed(5000) `

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

สถาปัตยกรรม MVI ใน Android
บทความที่เกี่ยวข้อง:
คู่มือฉบับสมบูรณ์เกี่ยวกับสถาปัตยกรรม MVI ใน Android

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


Surfshark Antivirus สำหรับ Android
อาจสนใจ:
วิธีการกำจัดไวรัสบน Android: คู่มือฉบับสมบูรณ์และอัปเดตเกี่ยวกับการทำความสะอาดโทรศัพท์ของคุณ
เพิ่มเป็นแหล่งข้อมูลที่ต้องการใน Google