如何在Kotlin的Method Channel中实现回调/协程以异步返回数据
实现方案
核心思路是暂存Method Channel返回的Result对象,等目标回调触发、数据准备完成后再调用该对象的返回方法将数据传回Flutter端,具体实现步骤如下:
1. 先声明必要的全局成员变量
// 暂存Method Channel的返回对象 private var pendingResult: MethodChannel.Result? = null // 登录状态标记 private var userLogged = false // 待返回的数据集 private val list: MutableList<String> = ArrayList() // 定义Channel常量,替换为你实际的Channel名 private val CHANNEL = "自定义channel名称"
2. 改造MethodCallHandler的登录逻辑
不要在loginChannel被调用时当场返回数据,仅暂存Result对象并触发你的登录/数据获取流程即可:
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { GeneratedPluginRegistrant.registerWith(flutterEngine); super.configureFlutterEngine(flutterEngine) MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL) .setMethodCallHandler { call: MethodCall, result: MethodChannel.Result -> when(call.method) { "createChannel" -> { // 你的原有逻辑 } "loginChannel" -> { if (!userLogged) { // 暂存返回对象,不要当场调用success pendingResult = result // 触发你的登录/数据获取流程,比如调用第三方登录接口、异步任务 startLoginAction() } else { // 如果已经登录/数据已就绪可以直接返回 result.success(list.toString()) } } else -> result.notImplemented() } } }
3. 在数据准备完成的回调中触发返回
在你提到的另一个触发函数(比如登录成功回调、异步数据获取完成回调)中,调用之前暂存的pendingResult返回数据即可:
// 这就是你说的另一个触发函数,比如登录成功的回调 private fun onDataReady() { userLogged = true // 这里可以给list赋值你要返回的最新数据 // list.add("返回数据1") // list.add("返回数据2") // 必须切主线程调用Result的返回方法,避免子线程调用报错 runOnUiThread { // 返回数据给Flutter端 pendingResult?.success(list.toString()) Toast.makeText(this, list.toString(), Toast.LENGTH_LONG).show() // 用完必须置空,避免重复调用Result抛异常 pendingResult = null } } // 可选:流程出错的情况也要处理,返回错误信息后同样置空pendingResult private fun onActionError(errorMsg: String) { runOnUiThread { pendingResult?.error("ACTION_ERROR", errorMsg, null) pendingResult = null } }
注意事项
MethodChannel.Result的success/error/notImplemented方法只能调用一次,调用完成后必须将暂存的pendingResult置空,否则二次调用会直接崩溃- 必须在Android主线程调用
Result的返回方法,如果你的回调运行在子线程,务必通过runOnUiThread切换线程 - 如果页面销毁时还未触发回调,要手动将
pendingResult置空,避免内存泄漏
内容的提问来源于stack exchange,提问作者Jakub Kořenek
相关产品推荐
相关产品推荐

