EventChannel.EventSink初始化问题及Flutter串口插件崩溃修复求助
问题
我正在开发Flutter串口通信插件,基于serial_communication包,但应用持续崩溃。我只熟悉Flutter开发,需要Java相关的技术支持。
错误日志
E/AndroidRuntime(21246): java.lang.NullPointerException: Attempt to invoke interface method 'void io.flutter.plugin.common.EventChannel$EventSink.success(java.lang.Object)' on a null object reference E/AndroidRuntime(21246): at com.example.serial_communication.CustomEventHandler.lambda$sendEvent$0(CustomStreamHandler.java:43) E/AndroidRuntime(21246): at com.example.serial_communication.CustomEventHandler$$ExternalSyntheticLambda0.run(D8$$SyntheticClass)
相关Java代码
class CustomEventHandler extends BroadcastReceiver implements EventChannel.StreamHandler { static EventChannel.EventSink events; static final Handler mainHandler = new Handler(Looper.getMainLooper()); @Override public void onListen(Object arguments, EventChannel.EventSink events) { this.events = events; } @Override public void onCancel(Object arguments) { events = null; } static void sendEvent(final Map<String,String> response) { System.out.println("sendEvent response 1 " + response); System.out.println("sendEvent events 1 " + events); System.out.println("sendEvent mainHandler 1 " + mainHandler); if (response != null && events != null && mainHandler != null) { System.out.println("sendEvent response 2 " + response); System.out.println("sendEvent response isEmpty 2 " + response.isEmpty()); System.out.println("sendEvent events 2 " + events); System.out.println("sendEvent mainHandler 2 " + mainHandler); Runnable runnable = () -> events.success(response); if(runnable != null) { mainHandler.post(runnable); } } else { System.out.println("sendEvent failed " + response + events + mainHandler); } } @Override public void onReceive(Context context, Intent intent) { if (events != null) { events.success("Hello"); } } }
日志对比
正常运行时日志
sendEvent response 1 {readChannel=fafb410040, LogChannel=Write a successful:fafb420043} sendEvent events 1 io.flutter.plugin.common.EventChannel$IncomingStreamRequestHandler$EventSinkImplementation@b3930ac sendEvent mainHandler 1 Handler (android.os.Handler) {5365175} sendEvent response 2 {readChannel=fafb410040, LogChannel=Write a successful:fafb420043} sendEvent response isEmpty 2 false sendEvent events 2 io.flutter.plugin.common.EventChannel$IncomingStreamRequestHandler$EventSinkImplementation@b3930ac sendEvent mainHandler 2 Handler (android.os.Handler) {5365175}
崩溃时日志
sendEvent response 1 {readChannel=fafb521934010100ff000000000000000000003030303030303030303081, LogChannel=Write a successful:fafb420043} sendEvent events 1 null sendEvent mainHandler 1 Handler (android.os.Handler) {5365175}
问题核心:尽管在sendEvent中添加了空值检查,仍出现events为空的空指针异常,需确保EventChannel.EventSink正确初始化,或找到其他修复方法。
解决方案
1. 修复竞态条件
空指针的本质是检查与调用之间的竞态:你检查events != null后,onCancel可能在mainHandler.post(runnable)之前被调用,将events置为null,导致Runnable执行时events已失效。
解决方式:创建Runnable前捕获当前的events实例,避免后续被修改:
static void sendEvent(final Map<String,String> response) { System.out.println("sendEvent response 1 " + response); System.out.println("sendEvent events 1 " + events); System.out.println("sendEvent mainHandler 1 " + mainHandler); // 捕获当前的events实例,隔离后续修改 EventChannel.EventSink currentEvents = events; if (response != null && currentEvents != null && mainHandler != null) { System.out.println("sendEvent response 2 " + response); System.out.println("sendEvent response isEmpty 2 " + response.isEmpty()); System.out.println("sendEvent events 2 " + currentEvents); System.out.println("sendEvent mainHandler 2 " + mainHandler); // 使用捕获的currentEvents,而非静态变量events Runnable runnable = () -> currentEvents.success(response); mainHandler.post(runnable); } else { System.out.println("sendEvent failed " + response + events + mainHandler); } }
2. 同步修复onReceive方法
onReceive中同样存在竞态风险,需同步处理:
@Override public void onReceive(Context context, Intent intent) { EventChannel.EventSink currentEvents = events; if (currentEvents != null) { currentEvents.success("Hello"); } }
3. 移除静态变量,改用实例变量
静态的events会导致生命周期不一致:Flutter组件销毁取消监听后,静态变量可能残留旧引用,或重新监听时覆盖不及时。建议改为实例变量,确保每个CustomEventHandler实例绑定独立的EventSink:
class CustomEventHandler extends BroadcastReceiver implements EventChannel.StreamHandler { // 移除static修饰,改为实例变量 private EventChannel.EventSink events; private final Handler mainHandler = new Handler(Looper.getMainLooper()); @Override public void onListen(Object arguments, EventChannel.EventSink events) { this.events = events; } @Override public void onCancel(Object arguments) { this.events = null; } // 移除static修饰,改为实例方法 void sendEvent(final Map<String,String> response) { EventChannel.EventSink currentEvents = this.events; if (response != null && currentEvents != null && mainHandler != null) { Runnable runnable = () -> currentEvents.success(response); mainHandler.post(runnable); } else { System.out.println("sendEvent failed " + response + currentEvents + mainHandler); } } @Override public void onReceive(Context context, Intent intent) { EventChannel.EventSink currentEvents = this.events; if (currentEvents != null) { currentEvents.success("Hello"); } } }
4. 确保EventChannel与插件生命周期绑定
在插件主类中,要保证CustomEventHandler实例与插件生命周期同步,避免重复注册或泄漏:
public class SerialCommunicationPlugin implements FlutterPlugin { private CustomEventHandler eventHandler; @Override public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) { eventHandler = new CustomEventHandler(); // 注册EventChannel并绑定handler new EventChannel(flutterPluginBinding.getBinaryMessenger(), "serial_communication/events") .setStreamHandler(eventHandler); // 注册BroadcastReceiver(按需调整IntentFilter) flutterPluginBinding.getApplicationContext() .registerReceiver(eventHandler, new IntentFilter("your_serial_action")); } @Override public void onDetachedFromEngine(@NonNull FlutterPluginBinding flutterPluginBinding) { // 注销BroadcastReceiver flutterPluginBinding.getApplicationContext().unregisterReceiver(eventHandler); // 清空EventChannel的handler new EventChannel(flutterPluginBinding.getBinaryMessenger(), "serial_communication/events") .setStreamHandler(null); } }
内容的提问来源于stack exchange,提问作者Izzati
相关产品推荐
相关产品推荐

