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 } }
为什么原代码不行?
- 主线程死锁:
runBlocking在主线程执行时会阻塞主线程,而MethodChannel的回调必须在主线程触发,导致回调无法执行,永远卡在等待状态。 - resume参数错误:原代码里
it.resume(res)传递的是初始值null,而不是Flutter返回的result,逻辑完全错误。
内容的提问来源于stack exchange,提问作者Nicerday
相关产品推荐
相关产品推荐

