我如何等待Kotlin协程中的其他事件?

时间:2019-04-26 15:31:03

标签: android kotlin kotlin-coroutines

在Kotlin中,使用协同程序,我有一个工作是从单击按钮开始的,并且不应该在调用活动的onStop之前结束。

看起来像这样的东西:

button.setOnClickListener {
    CoroutineScope(...).launch{
        print("Button clicked")

        // How to wait for "onStop()" ?

        print("Activity stopped")
    }
}

以上场景只是一般需要合并的一个示例 来自SDK内部的异步事件,以函数调用(onStop()的形式出现。

应该怎么做?谢谢:]

3 个答案:

答案 0 :(得分:3)

我会为按钮创建一个特殊的通道,而不是从onStop(0)发送一些东西给它,然后在您的代码中等待它:

val onStopChannel = Channel<Int>()

fun onStop() {
    onStopChannel.offer(0)
}

button.setOnClickListener {
    CoroutineScope(...).launch{
        print("Button clicked")

        onStopChannel.receive()

        print("Activity stopped")
    }
}

其他可观察到的东西也可以工作。

答案 1 :(得分:2)

要解决以下问题:

通常需要合并来自内部的异步事件 函数调用形式的SDK

我想补充一点,标准库将来自另一个不使用协程的库或API的异步回调或期货集成到您自己的使用协程的代码中的方法是suspendCoroutine函数。它暂停当前协程的执行,并使用一个非暂停的lambda,在其中注册您的回调/侦听器,当调用该回调/侦听器时,它将通过Continuation对象告诉协程以特定值恢复执行暂停功能或从回调获得的异常。

例如,在网络请求的情况下:

suspend fun useValueFromApiCall(apiCall: Call<Thing>) {
    val myThing: Thing = suspendCoroutine<Thing> { continuation ->
        apiCall.enqueue(object: Callback<Thing> {
            override fun onResponse(call: Call<Thing>, response: Response<Thing>) {
                continuation.resume(response.body()) // assign response.body() to myThing
            }
            override fun onFailure(call: Call<Thing>, t: Throwable) {
                continuation.resumeWithException(t) // throw t
            }
        })
    }
    // coroutine will suspend execution until the API call returns and
    // either myThing contains the response or an exception was thrown
    myThing.doSomething()
}

Here is a snippet很好地解释了这里的情况。

答案 2 :(得分:0)

我将使用join()函数等待我的工作,然后在onStop()回调中将其取消。 像这样:

class MainActivity : AppCompatActivity() {
    private var job: Job = Job()
    private val mainDispatchersContext = CoroutineScope(Dispatchers.Main)
    private val coroutineContext = CoroutineScope(Dispatchers.Main + job)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mainDispatchersContext.launch {
            doJob()
        }
    }

    private suspend fun doJob() {
        coroutineContext.launch {
            // do something
            Log.v(TAG, "Job started")
            job.join()
            Log.v(TAG, "This line is not executed")
        }
    }

    override fun onStop() {
        super.onStop()
        job.cancel()
        Log.v(TAG, "Job end")
    }

    companion object{
        const val TAG = "MainActivity"
    }
}