You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Kotlin中是否有方法等待获取MaterialAlertDialogBuilder的返回值?

基于Kotlin协程实现等待AlertDialog用户输入的最佳实践

对于将回调式API转为同步调用风格的需求,Kotlin协程官方推荐使用suspendCancellableCoroutine桥接回调,既可以实现等待用户操作返回结果再执行后续代码的需求,也符合Android协程的最佳实践。

注意事项

  • 不要使用GlobalScope启动协程,推荐使用和页面生命周期绑定的lifecycleScope(Activity/Fragment场景)或者viewModelScope(ViewModel场景),避免对话框未关闭时页面销毁导致的内存泄漏
  • 封装后的挂起函数必须在协程作用域内调用

实现代码

1. 封装对话框挂起函数

import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume

// 封装成挂起函数,返回用户输入的字符串,点取消/关闭对话框返回null
suspend fun showInputNameDialog(context: Context): String? = suspendCancellableCoroutine { continuation ->
    val customAlertDialogView = LayoutInflater.from(context)
        .inflate(R.layout.dialod_input_et, null, false)
    val inputNameEt = customAlertDialogView.findViewById<EditText>(R.id.input_dialog_et)

    val dialog = MaterialAlertDialogBuilder(context)
        .setView(customAlertDialogView)
        .setTitle("Type the name")
        .setPositiveButton("Accept", null) // 先设置空点击,后续自定义逻辑避免空输入自动关闭对话框
        .setNegativeButton("Cancel") { _, _ ->
            if (continuation.isActive) {
                continuation.resume(null)
            }
        }
        .setOnDismissListener {
            if (continuation.isActive) {
                continuation.resume(null)
            }
        }
        .create()

    // 自定义确认按钮点击逻辑
    dialog.setOnShowListener {
        dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
            val inputContent = inputNameEt.text.toString().trim()
            if (inputContent.isEmpty()) {
                Toast.makeText(context, "Type a name", Toast.LENGTH_SHORT).show()
                return@setOnClickListener
            }
            if (continuation.isActive) {
                continuation.resume(inputContent)
            }
            dialog.dismiss()
        }
    }

    // 协程取消时自动关闭对话框
    continuation.invokeOnCancellation {
        dialog.dismiss()
    }

    dialog.show()
}

2. 调用示例(Fragment场景)

// 比如在按钮点击事件中触发
lifecycleScope.launch {
    // 此处会挂起,直到用户操作对话框返回结果后才会执行后续代码
    val inputName = showInputNameDialog(requireContext())
    // 用户点击取消/关闭对话框时直接终止后续逻辑
    inputName ?: return@launch

    // 拿到输入结果后的后续业务逻辑
    nameToDisplay = inputName
    // 其他业务代码...
}

原有代码问题说明

你之前的实现没有生效,主要有两个原因:

  1. 你使用GlobalScope.launch启动了顶层协程,没有在当前执行流程中等待async的返回结果,代码在调用show()之后直接继续执行,自然拿不到异步返回的输入值
  2. GlobalScope没有和页面生命周期绑定,如果对话框还没关闭页面就被销毁,会导致内存泄漏

内容的提问来源于stack exchange,提问作者madbeans

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 14:27:02