LoginSignup
3
3

More than 5 years have passed since last update.

Androidで kotlinx.coroutines の channel の動作確認をした

Last updated at Posted at 2018-08-23

参考

Channelの基本

Channelの種類

クラス名 説明
Channel Channelのレシーバーが一つの場合に使用する。
BroadcastChannel Channelのレシーバーが複数存在する場合に使用する。

Channelの要素を追加する方法

メソッド名 説明
send()
offer() suspendファンクション外で要素を追加する。

Channelの要素を消費する方法

メソッド名 説明
receive()
select式 https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md#select-expression
consumeEach() https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md#building-channel-producers

動作確認コード



class MainActivity : AppCompatActivity(), AnkoLogger {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        test1()
        test2()
        test3()
        test3a()
        test4()
        test4a()
        test5()
        test5a()
    }

    /**
     * receive()の後にsend()を呼び出した場合
     *
     * 実行ログ: 無し(receiveでブロックされるため、channel1.sendまで処理が進まない。)
     */
    private fun test1() {
        val channel = Channel<Int>()
        launch(UI) {
            val result = channel.receive()
            info("test1: ${result}")
            channel.send(1)
        }
    }

    /**
     * receive()とsend()を別のコルーチンで実行した場合
     *
     * 実行ログ:
     *   test2: 1
     */
    private fun test2() {
        val channel = Channel<Int>()
        launch(UI) {
            val result = channel.receive()
            info("test2: ${result}")
        }

        launch(UI) {
            channel.send(1)
        }
    }

    /**
     * 複数のコルーチンで一つのchannelをreceive()した場合
     *
     * 実行ログ:
     *   test3-1: 1
     *   test3-2: 2
     */
    private fun test3() {
        val channel = Channel<Int>()
        launch(UI) {
            val result = channel.receive()
            info("test3-1: ${result}")
        }

        launch(UI) {
            val result = channel.receive()
            info("test3-2: ${result}")
        }

        launch(UI) {
            channel.send(1)
            channel.send(2)
            channel.send(3)
        }
    }

    /**
     * test3をBroadcastChannelにした場合
     *
     * 実行ログ:
     *   test3a-1: 1
     *   test3a-2: 1
     */
    private fun test3a() {
        val channel = BroadcastChannel<Int>(10)
        launch(UI) {
            val result = channel.openSubscription().receive()
            info("test3a-1: ${result}")
        }

        launch(UI) {
            val result = channel.openSubscription().receive()
            info("test3a-2: ${result}")
        }

        launch(UI) {
            channel.send(1)
            channel.send(2)
        }
    }

    /**
     * 複数のコルーチンで一つのchannelをselectした場合
     *
     * 実行ログ:
     *   test4-1: 1
     *   test4-2: 2
     */
    private fun test4() {
        val channel = Channel<Int>()
        launch(UI) {
            select<Unit> {
                channel.onReceive { value ->  // this is the first select clause
                    info("test4-1: ${value}")
                }
            }
        }

        launch(UI) {
            select<Unit> {
                channel.onReceive { value ->
                    info("test4-2: ${value}")
                }
            }
        }

        launch(UI) {
            channel.send(1)
            channel.send(2)
        }
    }

    /**
     * test4をBroadcastChannelにした場合
     *
     * 実行ログ:
     *   test4a-1: 1
     *   test4a-2: 1
     */
    private fun test4a() {
        val channel = BroadcastChannel<Int>(10)

        launch(UI) {
            select<Unit> {
                channel.openSubscription().onReceive { value ->
                    info("test4a-1: ${value}")
                }
            }
        }

        launch(UI) {
            select<Unit> {
                channel.openSubscription().onReceive { value ->
                    info("test4a-2: ${value}")
                }
            }
        }

        launch(UI) {
            channel.send(1)
            channel.send(2)
        }
    }

    /**
     * 複数のコルーチンで一つの channel を consumeEach した場合
     *
     * 実行ログ:
     *   test5-1: 1
     *   test5-2: 2
     */
    private fun test5() {
        val channel = Channel<Int>()
        launch(UI) {
            channel.consumeEach {
                info("test5-1: ${it}")
            }
        }

        launch(UI) {
            channel.consumeEach {
                info("test5-2: ${it}")
            }
        }

        launch(UI) {
            channel.send(1)
            channel.send(2)
        }
    }

    /**
     * test5をBroadcastChannelにした場合
     *
     * 実行ログ:
     *   test5a-1: 1
     *   test5a-1: 2
     *   test5a-2: 1
     *   test5a-2: 2
     */
    private fun test5a() {
        val channel = BroadcastChannel<Int>(10)
        launch(UI) {
            channel.consumeEach {
                info("test5a-1: ${it}")
            }
        }

        launch(UI) {
            channel.consumeEach {
                info("test5a-2: ${it}")
            }
        }

        launch(UI) {
            channel.send(1)
            channel.send(2)
        }
    }
}

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3