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

Android端调用Flutter MethodChannel并等待返回结果的实现方案

Android端同步获取Flutter MethodChannel返回值(避免UI冻结)

你遇到的问题核心是主线程阻塞死锁:用runBlocking在主线程等待回调时,MethodChannel的success回调本身也是在主线程执行的,runBlocking占着主线程不放,导致回调永远无法触发,最终UI卡死。另外原代码里it.resume(res)是错误的,应该传入Flutter返回的result。

下面给出两种可行方案,优先推荐协程非阻塞方式:

方案一:用协程suspend函数(推荐)

把获取数据的逻辑封装成suspend函数,在协程作用域中调用,完全不会阻塞UI:

// 定义suspend函数,用于在协程中获取Flutter返回值
suspend fun getFlutterData(): String? = suspendCoroutine { continuation ->
    channel?.invokeMethod(flutterMethod, params, object : MethodChannel.Result {
        override fun success(result: Any?) {
            // 将Flutter返回的结果传递给协程
            continuation.resume(result as? String)
        }

        override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) {
            // 出错时返回null,或者根据需求抛出异常
            // continuation.resumeWithException(Exception(errorMessage))
            continuation.resume(null)
        }

        override fun notImplemented() {
            continuation.resume(null)
        }
    })
}

调用方式(在协程作用域中)

比如在Activity的lifecycleScope或者ViewModel的viewModelScope中调用:

// 在Activity中
lifecycleScope.launch {
    val flutterData = getFlutterData()
    // 在这里直接处理返回数据,UI不会冻结
    tvContent.text = flutterData
}

// 在ViewModel中
viewModelScope.launch {
    val flutterData = getFlutterData()
    // 更新LiveData通知UI
    _dataLiveData.value = flutterData
}

方案二:CountDownLatch同步获取(不推荐,仅作兼容)

如果一定要用同步方式获取,必须在子线程中使用CountDownLatch,绝对不能在主线程调用,否则依然会冻结UI:

fun getFlutterDataSync(): String? {
    val latch = CountDownLatch(1)
    var result: String? = null

    channel?.invokeMethod(flutterMethod, params, object : MethodChannel.Result {
        override fun success(res: Any?) {
            result = res as? String
            latch.countDown() // 通知等待线程可以继续
        }

        override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) {
            latch.countDown()
        }

        override fun notImplemented() {
            latch.countDown()
        }
    })

    try {
        // 设置超时时间,避免无限等待
        latch.await(5, TimeUnit.SECONDS)
    } catch (e: InterruptedException) {
        e.printStackTrace()
    }

    return result
}

调用方式(必须在子线程)

// 开启子线程调用同步方法
Executors.newSingleThreadExecutor().execute {
    val data = getFlutterDataSync()
    // 回到主线程更新UI
    runOnUiThread {
        tvContent.text = data
    }
}

为什么原代码不行?

  1. 主线程死锁:runBlocking在主线程执行时会阻塞主线程,而MethodChannel的回调必须在主线程触发,导致回调无法执行,永远卡在等待状态。
  2. resume参数错误:原代码里it.resume(res)传递的是初始值null,而不是Flutter返回的result,逻辑完全错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 00:37:36