P7 Ali boss teaches you to crack Kotlin coroutines (10) - Select articles

Cracking Kotlin coroutines (10) - Select articles

insert image description here

Keywords: Kotlin coroutine Select multiplexing

Select is not a new concept, we have seen it in IO multiplexing, and we have seen it in Java NIO. Next, I will introduce to you the Select of Kotlin coroutine.

Reuse multiple await

We have touched a lot of suspending functions before, so if I have such a scenario, two APIs obtain data from the network and local cache respectively, and which one is expected to return first will be used for display:

fun CoroutineScope.getUserFromApi(login: String) = async(Dispatchers.IO){
    
    
    gitHubServiceApi.getUserSuspend(login)
}

fun CoroutineScope.getUserFromLocal(login:String) = async(Dispatchers.IO){
    
    
    File(localDir, login).takeIf {
    
     it.exists() }?.readText()?.let {
    
     gson.fromJson(it, User::class.java) }
}

No matter which API Deferredis awaitvalue will be suspended. If you want to realize this requirement, you need to start two coroutines to call await, which will make the problem more complicated.

Next we use selectto solve this problem:

GlobalScope.launch {
    
    
    val localDeferred = getUserFromLocal(login)
    val remoteDeferred = getUserFromApi(login)

    val userResponse = select<Response<User?>> {
    
    
        localDeferred.onAwait {
    
     Response(it, true) }
        remoteDeferred.onAwait {
    
     Response(it, false) }
    }
    ...
}.join()

As you can see, we did not call directly await, but onAwaitcalled selecta callback registered in , no matter which one is called back first, selectthe result in the corresponding callback will be returned immediately. Assuming that returns localDeferred.onAwaitfirst , then userResponsethe value of is Response(it, true), of course, because our local cache may not exist, so selectthe result type of is Response<User?>.

For this case itself, if the local cache is returned first, then we also need to obtain the network results to display the latest results:

GlobalScope.launch {
    
    
    ...
    userResponse.value?.let {
    
     log(it) }
    userResponse.isLocal.takeIf {
    
     it }?.let {
    
    
        val userFromApi = remoteDeferred.await()
        cacheUser(login, userFromApi)
        log(userFromApi)
    }
}.join()

Multiplexing multiple Channels

For Channelmultiple , it is similar:

val channels = List(10) {
    
     Channel<Int>() }

select<Int?> {
    
    
    channels.forEach {
    
     channel ->
        channel.onReceive {
    
     it }
        // OR
        channel.onReceiveOrNull {
    
     it }
    }
}

For onReceive, if Channelis closed, selectan exception will be thrown directly; for onReceiveOrNullif Channelit is closed, itthe value of is null.

SelectClause

How do we know which events can be selectcalled ? In fact, all events that can be selecttyped are SelectClauseNof type, including:

  • SelectClause0: The corresponding event has no return value. For example, jointhere is no return value, and the corresponding onJoinis this type onJoin. The parameter of is a no-argument function:select<Unit> { job.onJoin { log("Join resumed!") } }
  • SelectClause1: The corresponding event has a return value, and the preceding onAwaitand onReceiveare all such cases.
  • SelectClause2: The corresponding event has a return value, and an additional parameter is required, for example, Channel.onSendthere are two parameters, the first is a Channelvalue of data type, indicating the value to be sent, and the second is the callback when the send is successful: List(100) { element -> select<Unit> { channels.forEach { channel -> channel.onSend(element) { sentChannel -> log("sent on $sentChannel") } } } }in the consumer When the consumption efficiency is low, the data can be sent to whichever one can be sent for processing, and the onSendsecond parameter of the parameter is Channelthe object .

Therefore, if you want to confirm whether the suspend function is supported select, SelectClauseNyou .

summary

In coroutines, the semantics of Select are similar to Java NIO or Unix IO multiplexing. Its existence allows us to easily implement 1 to N, and whichever comes first will be processed. Although Select and Channel are closer to business development than the coroutine API of the standard library, I personally think that they are still relatively low-level API packages, and in practice, Flow API can also be used to solve them in most cases.

And this Flow API is completely a coroutine API for responsive programming. We can learn it just like RxJava, so see you in the next article~~~

Kotlin coroutine learning materials can be obtained for free by scanning the QR code below!

"The most detailed Android version of kotlin coroutine entry advanced combat in history"

Chapter 1 Introduction to the Basics of Kotlin Coroutines

            ● 协程是什么

            ● 什么是Job 、Deferred 、协程作用域

            ● Kotlin协程的基础用法

img

Chapter 2 Preliminary Explanation of Key Knowledge Points of Kotlin Coroutine

            ● 协程调度器

            ● 协程上下文

            ● 协程启动模式

            ● 协程作用域

            ● 挂起函数

img

Chapter 3 Exception Handling of Kotlin Coroutines

            ● 协程异常的产生流程

            ● 协程的异常处理

img

Chapter 4 Basic application of kotlin coroutines in Android

            ● Android使用kotlin协程

            ● 在Activity与Framgent中使用协程

            ● ViewModel中使用协程

            ● 其他环境下使用协程

img

Chapter 5 Network request encapsulation of kotlin coroutine

            ● 协程的常用环境

            ● 协程在网络请求下的封装及使用

            ● 高阶函数方式

            ● 多状态函数返回值方式

Guess you like

Origin blog.csdn.net/Android_XG/article/details/130641992