Flutter插件Kotlin代码出现Reply already submitted异常如何解决?
Flutter PowerManager插件「Reply already submitted」异常修复
问题场景
开发Android proximity唤醒锁控制的Flutter插件时,调用方法抛出如下异常:
E/MethodChannel#powermanager(16953): Failed to handle method call E/MethodChannel#powermanager(16953): java.lang.IllegalStateException: Reply already submitted E/MethodChannel#powermanager(16953): at io.flutter.embedding.engine.dart.DartMessenger$Reply.reply(DartMessenger.java:435) E/MethodChannel#powermanager(16953): at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler$1.notImplemented(MethodChannel.java:273) E/MethodChannel#powermanager(16953): at com.powermanager.powermanager.PowermanagerPlugin.onMethodCall(PowermanagerPlugin.kt:55) E/MethodChannel#powermanager(16953): at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:258) E/MethodChannel#powermanager(16953): at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(DartMessenger.java:295) E/MethodChannel#powermanager(16953): at io.flutter.embedding.engine.dart.DartMessenger.lambda$dispatchMessageToQueue$0$io-flutter-embedding-engine-dart-DartMessenger(DartMessenger.java:322) E/MethodChannel#powermanager(16953): at io.flutter.embedding.engine.dart.DartMessenger$$ExternalSyntheticLambda0.run(Unknown Source:12) E/MethodChannel#powermanager(16953): at android.os.Handler.handleCallback(Handler.java:873) E/MethodChannel#powermanager(16953): at android.os.Handler.dispatchMessage(Handler.java:99) E/MethodChannel#powermanager(16953): at android.os.Looper.loop(Looper.java:193) E/MethodChannel#powermanager(16953): at android.app.ActivityThread.main(ActivityThread.java:6669) E/MethodChannel#powermanager(16953): at java.lang.reflect.Method.invoke(Native Method) E/MethodChannel#powermanager(16953): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) E/MethodChannel#powermanager(16953): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
原Kotlin插件代码
package com.powermanager.powermanager import android.content.Context import android.os.PowerManager import androidx.annotation.NonNull import io.flutter.embedding.engine.plugins.FlutterPlugin import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.MethodChannel.MethodCallHandler import io.flutter.plugin.common.MethodChannel.Result /** PowermanagerPlugin */ class PowermanagerPlugin: FlutterPlugin, MethodCallHandler { private lateinit var applicationContext: Context private lateinit var channel : MethodChannel private lateinit var powerManager: PowerManager private lateinit var lock: PowerManager.WakeLock override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { applicationContext = flutterPluginBinding.getApplicationContext(); channel = MethodChannel(flutterPluginBinding.binaryMessenger, "powermanager") channel.setMethodCallHandler(this) powerManager = applicationContext.getSystemService(Context.POWER_SERVICE) as PowerManager if(powerManager.isWakeLockLevelSupported(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)) { lock = powerManager.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK,"PROXIMITYSCREENOFFWAKELOCK") lock.setReferenceCounted(false) } } override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { if (call.method == "on") { if(powerManager.isWakeLockLevelSupported(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)) { if(lock.isHeld) { lock.release(1) } lock.acquire() result.success(true) } else { result.error("notSupported", "PowerManager PROXIMITY_SCREEN_OFF_WAKE_LOCK is notSupported", null) } } else { result.notImplemented() } if (call.method == "off") { if(powerManager.isWakeLockLevelSupported(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)) { if(lock.isHeld) { lock.release(1) } result.success(true) } else { result.error("notSupported", "PowerManager PROXIMITY_SCREEN_OFF_WAKE_LOCK is notSupported", null) } } else { result.notImplemented() } } override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { if(::lock.isInitialized) { if(lock.isHeld) { lock.release(1) } } channel.setMethodCallHandler(null) } }
Dart端调用代码
_powerManager(bool makeActive) async { try { if (makeActive) { await Powermanager().on(); } else { await Powermanager().off(); } } catch (e) { debugPrint(e.toString()); } } @override void initState() { super.initState(); _powerManager(true); } @override void dispose() { _powerManager(false); super.dispose(); }
问题原因
核心问题是onMethodCall中存在两次独立的if判断逻辑,导致单个方法调用触发两次结果回复:
- 调用
on方法时,第一个if分支执行result.success(true),随后第二个if判断不成立,又执行result.notImplemented(),造成重复回复 - 调用
off方法时,第二个if分支执行result.success(true),第一个if的else分支再次执行result.notImplemented(),同样触发重复回复
Flutter的MethodChannel要求每个方法调用只能回复一次结果,重复调用result.success/error/notImplemented就会抛出Reply already submitted异常。
修复方案
将onMethodCall中的独立if改为if-else if或Kotlinwhen表达式,确保每个方法调用只进入一个分支,仅回复一次结果:
修复后的Kotlin插件代码(使用when表达式)
package com.powermanager.powermanager import android.content.Context import android.os.PowerManager import androidx.annotation.NonNull import io.flutter.embedding.engine.plugins.FlutterPlugin import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.MethodChannel.MethodCallHandler import io.flutter.plugin.common.MethodChannel.Result /** PowermanagerPlugin */ class PowermanagerPlugin: FlutterPlugin, MethodCallHandler { private lateinit var applicationContext: Context private lateinit var channel : MethodChannel private lateinit var powerManager: PowerManager private lateinit var lock: PowerManager.WakeLock override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { applicationContext = flutterPluginBinding.getApplicationContext(); channel = MethodChannel(flutterPluginBinding.binaryMessenger, "powermanager") channel.setMethodCallHandler(this) powerManager = applicationContext.getSystemService(Context.POWER_SERVICE) as PowerManager if(powerManager.isWakeLockLevelSupported(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)) { lock = powerManager.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK,"PROXIMITYSCREENOFFWAKELOCK") lock.setReferenceCounted(false) } } override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { when(call.method) { "on" -> { if(powerManager.isWakeLockLevelSupported(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)) { if(lock.isHeld) { lock.release(1) } lock.acquire() result.success(true) } else { result.error("notSupported", "PowerManager PROXIMITY_SCREEN_OFF_WAKE_LOCK is notSupported", null) } } "off" -> { if(powerManager.isWakeLockLevelSupported(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)) { if(lock.isHeld) { lock.release(1) } result.success(true) } else { result.error("notSupported", "PowerManager PROXIMITY_SCREEN_OFF_WAKE_LOCK is notSupported", null) } } else -> result.notImplemented() } } override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { if(::lock.isInitialized) { if(lock.isHeld) { lock.release(1) } } channel.setMethodCallHandler(null) } }
如果偏好传统if-else if结构,也可以替换为:
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { if (call.method == "on") { if(powerManager.isWakeLockLevelSupported(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)) { if(lock.isHeld) { lock.release(1) } lock.acquire() result.success(true) } else { result.error("notSupported", "PowerManager PROXIMITY_SCREEN_OFF_WAKE_LOCK is notSupported", null) } } else if (call.method == "off") { if(powerManager.isWakeLockLevelSupported(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)) { if(lock.isHeld) { lock.release(1) } result.success(true) } else { result.error("notSupported", "PowerManager PROXIMITY_SCREEN_OFF_WAKE_LOCK is notSupported", null) } } else { result.notImplemented() } }
额外优化提示
- 可在
onAttachedToEngine中提前判断唤醒锁支持情况,避免每次方法调用重复判断 - 若不需要返回结果,直接调用
result.success(null)即可,不可省略回复步骤
内容的提问来源于stack exchange,提问作者Cenk YAGMUR
相关产品推荐
相关产品推荐

