Android Kotlin Flow 如何使用callbackflow
轉載請標明出處:http://blog.csdn.net/zhaoyanjun6/article/details/121840157
本文出自【趙彥軍的博客】
callbackFlow 原理
callbackFlow:底層使用channel來進行中轉,首先通過produce創建一個ReceiveChannel。然后在調用collect的時候,在將channel的值取出來emit出去。
首先我們來看一個例子:
我們有一個網絡接口,在耗時3秒后會回調一個結果,把結果 3 ,回調出去。代碼如下:
/*** 模擬網絡請求*/fun requestApi(block: (Int) -> Unit) {thread {Thread.sleep(3000)block(3)}}如果我們要把這個用 Flow 的形式把結果發送出去改怎么寫:
GlobalScope.launch {val flow = flow {//模擬網絡請求requestApi {emit(1)}}flow.collect {Log.d("list-", "$it")}}你以為沒問題,其實根本行不通,會報錯
報錯的意思是:掛起函數只能在協程體內使用,也就是 emit 方法時一個掛起函數,只能用在協程體內。
那該怎么處理呢?用 callbackFlow 就可以了。
什么是 callbackFlow?官方的答案是:將基于回調的 API 轉換為數據流。
callbackFlow 是冷流,沒有接收者,不會產生數據。
地址是:https://developer.android.com/kotlin/flow
我們來試試看:
val flow = callbackFlow {//模擬網絡請求回調requestApi { result ->//發送數據offer(result)}}GlobalScope.launch {flow.collect {//接收結果 }}發現運行起來就崩潰了,拋出以下日志:
java.lang.IllegalStateException: 'awaitClose { yourCallbackOrListener.cancel() }' should be used in the end of callbackFlow block.
意思是:要在 callbackFlow block 體中,調用 awaitClose 方法。
awaitClose 方法是:當數據接收者所在的協程被關閉的時候會調用,作用是:用來釋放資源,比如取消網絡請求、斷開io流、移除監聽器、釋放內存 等等。
也就是調用 job.cancel() 的時候,會調用 awaitClose。
完整示例如下:
模擬網絡請求、模擬取消網絡請求
/*** 模擬網絡請求*/fun requestApi(block: (Int) -> Unit) {thread {Log.d("list-", "網絡請求")Thread.sleep(3000)block(3)}}/*** 模擬取消網絡請求*/fun cancelApi(){//do some thing}callbackFlow 如下:
val flow = callbackFlow {//模擬網絡請求回調requestApi { result ->//發送數據offer(result)}awaitClose { //當數據接收者所在的協程被關閉的時候會調用。//作用是:用來釋放資源cancelApi()}}val job = GlobalScope.launch {flow.collect {//接收結果}}在產生數據的時候,有兩個方法給我用:send 、offer
- send : 必須在協程體內使用
- offer : 可以在非協程體內使用
事實上,offer 是 Channel 的方法。
關于 awaitClose
其實很簡單嘛,其實就是一個掛起函數,直到接收到 channel 的invokeOnClose回調,才會resume回去。
那具體awaitClose什么時候被回調呢?換句話說,通過 callbackFlow 創建的 flow 什么時候可以被關閉呢?
取消流收集 cancel() 或基于回調的 API 手動調用 SendChannel.close() 時調用或外部的協程被取消時,才會調用awaitClose。換句話說,需要手動關閉創建的callbackFlow,否則就會一直處于運行狀態不會結束。
放一個官方的例子:
總結
以上是生活随笔為你收集整理的Android Kotlin Flow 如何使用callbackflow的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android Flow遇见Retrof
- 下一篇: OkHttp ResponseBody没