Kotlin Flow กับ LiveData


10

ใน Google I / O ล่าสุด Jose Alcerreca และ Yigit Boyar บอกกับเราว่าเราไม่ควรใช้ LiveData เพื่อดึงข้อมูลอีกต่อไป ตอนนี้เราควรใช้ฟังก์ชั่นระงับสำหรับการดึงข้อมูลครั้งเดียวและใช้ Flow ของ Kotlin เพื่อสร้างกระแสข้อมูล ฉันยอมรับว่า coroutines นั้นยอดเยี่ยมสำหรับการดึงข้อมูลแบบครั้งเดียวหรือการดำเนินการ CRUD อื่น ๆ เช่นการแทรกเป็นต้น แต่ในกรณีที่ฉันต้องการสตรีมข้อมูลฉันไม่เข้าใจว่าข้อดีของโฟลว์คืออะไร สำหรับฉันแล้วดูเหมือนว่า LiveData ก็ทำเช่นเดียวกัน

ตัวอย่างที่มี Flow:

ViewModel

val items = repository.fetchItems().asLiveData()

กรุ

fun fetchItems() = itemDao.getItems()

เชียงดาว

@Query("SELECT * FROM item")
fun getItems(): Flow<List<Item>>

ตัวอย่างด้วย LiveData:

ViewModel

val items = repository.fetchItems()

กรุ

fun fetchItems() = itemDao.getItems()

เชียงดาว

@Query("SELECT * FROM item")
fun getItems(): LiveData<List<Item>>

ฉันต้องการดูตัวอย่างของโครงการที่ใช้ coroutines และ Flow เพื่อทำงานกับ Room หรือ Retrofit ฉันพบเฉพาะตัวอย่างสิ่งที่ต้องทำของ Google ที่ใช้ coroutines สำหรับการดึงข้อมูลแบบครั้งเดียวแล้วดึงข้อมูลด้วยตนเองเมื่อมีการเปลี่ยนแปลง

คำตอบ:


3

Flowเป็นประเภทของreactive stream(เช่น rxjava) มีพวงของผู้ประกอบการที่แตกต่างกันเช่นมี.map, buffer()(อยู่แล้วน้อย no. ของผู้ประกอบการเมื่อเทียบกับ rxJava) ดังนั้นหนึ่งในความแตกต่างที่สำคัญระหว่างLiveDataและFlowคือคุณสามารถสมัครสมาชิกแผนที่computation / transformationในหัวข้ออื่น ๆ ที่ใช้

 flowOn(Dispatcher....). 

ดังนั้นสำหรับเช่น: -

 flowOf("A","B","C").map { compute(it) }.flowOn(Dispatchers.IO).collect {...} // U can change the execution thread of the computation ( by default its in the same dispatcher as collect )

ด้วยLiveDataและmapไม่สามารถทำได้โดยตรง!

ดังนั้นจึงแนะนำให้ไหลในระดับพื้นที่เก็บข้อมูลและทำให้ liveata เป็นสะพานเชื่อมระหว่าง UI และพื้นที่เก็บข้อมูล!

ความแตกต่างที่สำคัญคือflowมีผู้ให้บริการหลายรายซึ่งlivedataไม่มี! แต่มันก็ขึ้นอยู่กับคุณคุณอยากสร้างโครงการของคุณอย่างไร!


3

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

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

private fun render(stuffToPlay: List<Any>): Flow<Sample> = flow {
     val sample = Sample()
     // computationally intensive operation on stuffToPlay
     Thread.sleep(2000)
     emit(sample)
}

จากนั้นในฟังก์ชั่น 'เล่น' คุณสามารถแสดงผลลัพธ์ที่ stuffToPlay เป็นรายการของวัตถุที่จะแสดงเช่น:

playbackJob = GlobalScope.launch(Dispatchers.Default) {

    render(stuffToPlay)
        .buffer(1000)   // tells the Flow how many values should be calculated in advance

        .onCompletion {
            // gets called when all stuff got played
        }
        .collect{sample ->
           // collect the next value in the buffered queue
           // e.g. display sample
        }
}

คุณลักษณะที่สำคัญของ Flow คือโค้ดสร้าง (ฟังก์ชั่นการเรนเดอร์) ที่นี่จะได้รับการประมวลผลก็ต่อเมื่อได้รับการรวบรวมดังนั้นจึงเป็นสตรีมเย็น

คุณยังสามารถอ้างถึงเอกสารที่Asynchronous Flow

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.