成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

Kotlin協(xié)程Flow淺析-創(chuàng)新互聯(lián)

Kotlin協(xié)程中的Flow主要用于處理復(fù)雜的異步數(shù)據(jù),以一種”流“的方式,從上到下依次處理,和RxJava的處理方式類型,但是比后者更加強大。

我們注重客戶提出的每個要求,我們充分考慮每一個細(xì)節(jié),我們積極的做好網(wǎng)站設(shè)計、做網(wǎng)站服務(wù),我們努力開拓更好的視野,通過不懈的努力,成都創(chuàng)新互聯(lián)公司贏得了業(yè)內(nèi)的良好聲譽,這一切,也不斷的激勵著我們更好的服務(wù)客戶。 主要業(yè)務(wù):網(wǎng)站建設(shè),網(wǎng)站制作,網(wǎng)站設(shè)計,小程序定制開發(fā),網(wǎng)站開發(fā),技術(shù)開發(fā)實力,DIV+CSS,PHP及ASP,ASP.Net,SQL數(shù)據(jù)庫的技術(shù)開發(fā)工程師。Flow基本概念

Flow中基本上有三個概念,即 發(fā)送方,處理中間層,接收方,可以類比水利發(fā)電站中的上游,發(fā)電站,下游的概念, 數(shù)據(jù)從上游開始發(fā)送”流淌“至中間站被”處理“了一下,又流淌到了下游。

示例代碼如下

flow {         // 發(fā)送方、上游
    emit(1)    // 掛起函數(shù),發(fā)送數(shù)據(jù)
    emit(2)
    emit(3)
    emit(4)
    emit(5)
}
.filter { it >2 }  // 中轉(zhuǎn)站,處理數(shù)據(jù)
.map { it * 2 }
.take(2)
.collect{           // 接收方,下游
    println(it)
}
輸出內(nèi)容:
6
8

通過上面代碼我們可以看到,基于一種鏈?zhǔn)秸{(diào)用api的方式,流式的進(jìn)行處理數(shù)據(jù)還是很棒的,接下來具體看一下上面的組成:

  • flow{},是個高階函數(shù),主要用于創(chuàng)建一個新的Flow。在其Lambda函數(shù)內(nèi)部使用了emit()掛起函數(shù)進(jìn)行發(fā)送數(shù)據(jù)。
  • filter{}、map{}、take{},屬于中間處理層,也是中間數(shù)據(jù)處理的操作符,F(xiàn)low大的優(yōu)勢,就是它的操作符跟集合操作符高度一致。只要會用List、Sequence,那么就可以快速上手 Flow 的操作符。
  • collect{},下游接收方,也成為終止操作符,它的作用其實只有一個:終止Flow數(shù)據(jù)流,并且接收這些數(shù)據(jù)。

其他創(chuàng)建Flow的方式還是flowOf()函數(shù),示例代碼如下

fun main() = runBlocking{aassssssssaaaaaaaas
    flowOf(1,2,3,4,5).filter { it >2 }
        .map { it * 2 }
        .take(2)
        .collect{
            println("flowof: $it")
    }
}

我們在看一下list集合的操作示例

listOf(1,2,3,4,5).filter { it >2 }
        .map { it * 2 }
        .take(2)
        .forEach{
            println("listof: $it")
        }

通過以上對比發(fā)現(xiàn),兩者的基本操作幾乎一致,Kotlin也提供了兩者相互轉(zhuǎn)換的API,F(xiàn)low.toList()、List.asFlow()這兩個擴展函數(shù),讓數(shù)據(jù)在 List、Flow 之間來回轉(zhuǎn)換,示例代碼如下:

//flow 轉(zhuǎn)list
    flowOf(1,2,3)
        .toList()
        .filter { it >1 }
        .map { it * 2 }
        .take(2)
        .forEach{
            println(it)
        }
    // list 轉(zhuǎn) flow
    listOf(1,2,3).asFlow()
        .filter { it >2 }
        .map { it * 2 }
        .take(2)
        .collect{
            println(it)
        }
Flow生命周期

雖然從上面操作看和集合類型,但是Flow還是有些特殊操作符的,畢竟它是協(xié)程的一部分,和Channel不同,F(xiàn)low是有生命周期的,只是以操作符的形式回調(diào)而已,比如onStart、onCompletion這兩個中間操作符。

flowOf(1,2,3,4,5,6)
        .filter {
            println("filter: $it")
            it >3
        }
        .map {
            println("map: $it")
            it * 2
        }
        .take(2)
        .onStart { println("onStart") }
        .collect{
            println("collect: $it")
        }
輸出內(nèi)容:
onStart
filter: 1
filter: 2
filter: 3
filter: 4
map: 4
collect: 8
filter: 5
map: 5
collect: 10

我們可以看到onStart,它的作用是注冊一個監(jiān)聽事件:當(dāng) flow 啟動以后,它就會被回調(diào)。

和filter、map、take這些中間操作符不同,他們的順序會影響數(shù)據(jù)的處理結(jié)果,這也很好理解;onStart和位置沒有關(guān)系,它本質(zhì)上是一個回調(diào),不是一個數(shù)據(jù)處理的中間站。同樣的還有數(shù)據(jù)處理完成的回調(diào)onCompletion。

flowOf(1,2,3,4,5,6)
        .filter {
            println("filter: $it")
            it >3
        }
        .map {
            println("map: $it")
            it * 2
        }
        .take(2)
        .onStart { println("onStart") }
        .onCompletion { println("onCompletion") }
        .collect{
            println("collect: $it")
        }

Flow中onCompletion{} 在面對以下三種情況時都會進(jìn)行回調(diào):

  • 1,F(xiàn)low 正常執(zhí)行完畢
  • 2,F(xiàn)low 當(dāng)中出現(xiàn)異常
  • 3,F(xiàn)low 被取消。
處理異常

在數(shù)據(jù)流的處理過程中,很難保證不出現(xiàn)問題,那么出現(xiàn)異常之后再該怎么處理呢?

  • 對于發(fā)生在上游、中間操作這兩個階段的異常,我們可以直接使用 catch 這個操作符來進(jìn)行捕獲和進(jìn)一步處理。
  • 對于發(fā)生在下游,使用try-catch,把collect{}當(dāng)中可能出現(xiàn)問題的代碼包裹起來進(jìn)行捕獲處理。
上游或者中間異常使用catch
fun main() = runBlocking{
    val flow = flow {
        emit(1)
        emit(2)
        throw IllegalStateException()
        emit(3)
    }

    flow.map { it * 2 }
        .catch { println("catch: $it") }
        .collect{
            println("collect: $it")
        }
}
輸出:
collect: 2
collect: 4
catch: java.lang.IllegalStateException

catch 這個操作符的作用是和它的位置強相關(guān)的,catch 的作用域,僅限于catch的上游。換句話說,發(fā)生在 catch 上游的異常,才會被捕獲,發(fā)生在 catch 下游的異常,則不會被捕獲。

val flow = flow {
        emit(1)
        emit(2)
        throw IllegalStateException()
        emit(3)
    }

    flow.map { it * 2 }
        .catch { println("catch: $it") }
        .filter { it / 0 >1 } // catch之后發(fā)生異常
        .collect{
            println("collect: $it")
    }
輸出內(nèi)容:
Exception in thread "main" java.lang.ArithmeticException: / by zero
下游使用try-catch
flowOf(1,2,3)
        .onCompletion { println("onCompletion $it") }
        .collect{
            try {
                println("collect: $it")
                throw IllegalStateException();
            }catch (e: Exception){
                println("catch $e")
            }
        }
輸出:
collect: 1
catch java.lang.IllegalStateException
collect: 2
catch java.lang.IllegalStateException
collect: 3
catch java.lang.IllegalStateException
onCompletion null
切換執(zhí)行線程

Flow適合處理復(fù)雜的異步任務(wù),大多數(shù)情況下耗時任務(wù)放在子線程或線程池中處理,對于UI任務(wù)放在主線程中進(jìn)行。

在Flow中可以使用flowOn操作符實現(xiàn)上述場景中的線程切換。

flowOf(1,2,3,4,5)
        .filter {
            logX("filter: $it")
            it >2 }
        .flowOn(Dispatchers.IO) // 切換線程
        .collect{
            logX("collect: $it")
        }
輸出內(nèi)容:
================================
filter: 1
Thread:DefaultDispatcher-worker-1
================================
================================
filter: 2
Thread:DefaultDispatcher-worker-1
================================
================================
filter: 3
Thread:DefaultDispatcher-worker-1
================================
================================
filter: 4
Thread:DefaultDispatcher-worker-1
================================
================================
filter: 5
Thread:DefaultDispatcher-worker-1
================================
================================
collect: 3
Thread:main
================================
================================
collect: 4
Thread:main
================================
================================
collect: 5
Thread:main
================================

flowOn 操作符也是和它的位置強相關(guān)的。作用域限于它的上游。在上面的代碼中,flowOn 的上游,就是 flowOf{}、filter{} 當(dāng)中的代碼,所以,它們的代碼全都運行在 DefaultDispatcher 這個線程池當(dāng)中。只有collect{}當(dāng)中的代碼是運行在 main 線程當(dāng)中的。

終止操作符

Flow 里面,最常見的終止操作符就是collect。除此之外,還有一些從集合中借鑒過來的操作符,也是Flow的終止操作符。比如 first()、single()、fold{}、reduce{},本質(zhì)上來說說當(dāng)我們嘗試將 Flow 轉(zhuǎn)換成集合的時候,已經(jīng)不屬于Flow的API,也不屬于協(xié)程的范疇了,它本身也就意味著 Flow 數(shù)據(jù)流的終止。

"冷的數(shù)據(jù)流"從何而來

在上面文章《Kotlin協(xié)程Channel淺析》中,我們認(rèn)識到Channel是”熱數(shù)據(jù)流“,隨時準(zhǔn)備好,隨用隨取,就像海底撈里的服務(wù)員。

現(xiàn)在我們看下Flow和Channel的區(qū)別

val flow = flow {
        (1..4).forEach{
            println("Flow發(fā)送前:$it")
            emit(it)
            println("Flow發(fā)送后: $it")
        }
    }

    val channel: ReceiveChannel= produce {
        (1..4).forEach{
            println("Channel發(fā)送前: $it")
            send(it)
            println("Channel發(fā)送后: $it")
        }
    }
    
輸出內(nèi)容:
Channel發(fā)送前: 1

Flow中的邏輯并未執(zhí)行,因此我們可以這樣類比,Channel之所以被認(rèn)為是“熱”的原因,是因為不管有沒有接收方,發(fā)送方都會工作。那么對應(yīng)的,F(xiàn)low被認(rèn)為是“冷”的原因,就是因為只有調(diào)用終止操作符之后,F(xiàn)low才會開始工作。

除此之外,F(xiàn)low一次處理一條數(shù)據(jù),是個”懶家伙“。

val flow = flow {
        (3..6).forEach {
            println("Flow發(fā)送前:$it")
            emit(it)
            println("Flow發(fā)送后: $it")
        }
    }.filter {
        println("filter: $it")
        it >3
    }.map {
        println("map: $it")
        it * 2
    }.collect {
        println("結(jié)果collect: $it")
    }
輸出內(nèi)容:
Flow發(fā)送前:3
filter: 3
Flow發(fā)送后: 3
Flow發(fā)送前:4
filter: 4
map: 4
結(jié)果collect: 8
Flow發(fā)送后: 4
Flow發(fā)送前:5
filter: 5
map: 5
結(jié)果collect: 10
Flow發(fā)送后: 5
Flow發(fā)送前:6
filter: 6
map: 6
結(jié)果collect: 12
Flow發(fā)送后: 6

相比于滿面春風(fēng),熱情服務(wù)的Channel,Flow更像個冷漠的家伙,你不找他,他不搭理你。

  • Channel,響應(yīng)速度快,但數(shù)據(jù)可能是舊的,占用資源
  • Flow,響應(yīng)速度慢,但數(shù)據(jù)是最新的,節(jié)省資源

Flow也可以是”熱“的,你知道嗎?

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧

分享標(biāo)題:Kotlin協(xié)程Flow淺析-創(chuàng)新互聯(lián)
文章鏈接:http://jinyejixie.com/article34/dpsdpe.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供企業(yè)網(wǎng)站制作、營銷型網(wǎng)站建設(shè)網(wǎng)站內(nèi)鏈、定制網(wǎng)站、做網(wǎng)站、App開發(fā)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站建設(shè)
北安市| 姜堰市| 福贡县| 临洮县| 济源市| 莆田市| 诸城市| 泰州市| 西藏| 那曲县| 于田县| 宁陕县| 湛江市| 射阳县| 张掖市| 宜川县| 罗源县| 新宁县| 同仁县| 平湖市| 平南县| 九台市| 永清县| 黄冈市| 清水县| 乐亭县| 阿鲁科尔沁旗| 天等县| 南投市| 郧西县| 桃源县| 广饶县| 上饶县| 恩施市| 嘉兴市| 太湖县| 启东市| 房山区| 公安县| 沁水县| 修文县|