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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 00:23:10