首页 > 解决方案 > 调用 Continuation.resumeX() 失败一定是个问题吗?

问题描述

suspendCoroutine用来避免在Dialogs 中使用回调。但是,在 Android 中,当对话框关闭时(通过单击对话框区域外),Dialog没有明显的地方可以调用。Continuation.resume()如果您尝试调用,Dialog.setOnDismissListener()则必须跟踪是否已在按钮侦听器中调用了 resume。

suspend fun displayDialog() = suspendCoroutine<String?> { continuation ->
    val builder = AlertDialog.Builder(context)
    builder.setCancelable(true)
    builder.setNegativeButton(android.R.string.cancel) { _, _ ->
        continuation.resume(null)
    }
    builder.setPositiveButton(android.R.string.ok) { _, _ ->
        continuation.resume("it's ok")
    }
    val dialog = builder.show()
    dialog.setOnDismissListener {
        // if the user clicked on OK, then resume has already been called
        // and we get an IllegalStateException
        continuation.resume(null)
    }
}

那么,是否更好地跟踪是否已经调用了 resume(以避免再次调用它),或者只是不打扰resume(null)调用(在 onDismissListener 中)?

标签: kotlinandroid-dialogkotlin-coroutines

解决方案


Continuation 是一个低级原语,只能恢复一次,因此您必须resume在使用它时跟踪是否已经调用过它。或者,您可以使用更高级别的通信原语,例如CompletableDeferred,它具有多用途complete功能:

suspend fun displayDialog(): String? {
    val deferred = CompletableDeferred<String?>()
    val builder = AlertDialog.Builder(context)
    builder.setCancelable(true)
    builder.setNegativeButton(android.R.string.cancel) { _, _ ->
        deferred.complete(null)
    }
    builder.setPositiveButton(android.R.string.ok) { _, _ ->
        deferred.complete("it's ok")
    }
    val dialog = builder.show()
    dialog.setOnDismissListener {
        deferred.complete(null)
    }
    return deferred.await()
}

推荐阅读