使用EventChannel向Flutter发送读卡数据报FlutterJNI detached错误如何解决
问题根源
报错本质是原生侧调用EventSink发送消息时,对应的FlutterJNI已经和原生层分离,所持有的EventSink已失效,核心触发原因有3个:
- 原生
ICardEventCallHandler的onCancel回调中未将存储的events对象置空,也没有在发送消息前做有效性校验,失效的sink不会被自动清理 - Dart侧没有对EventChannel的订阅做生命周期绑定,页面销毁/APP退后台/Flutter引擎重启时未取消订阅,原生会一直持有失效的sink引用
- 你大概率将
ICardEventCallHandler作为全局单例使用,APP长时间在后台被系统回收Flutter引擎、或者二次启动时,旧的sink没有被新初始化的sink覆盖,直接调用就会触发报错
修复方案
1. 原生Java端修改
调整ICardEventCallHandler逻辑,增加空校验、异常捕获,取消监听时清空sink:
package com.test.handler.card; import com.alibaba.fastjson.JSON; import com.test.entity.ICard; import io.flutter.plugin.common.EventChannel; public class ICardEventCallHandler implements EventChannel.StreamHandler,EventSender{ private Object arguments; private EventChannel.EventSink events; @Override public void onListen(Object arguments, EventChannel.EventSink events) { this.arguments = arguments; // 每次新的监听覆盖旧的sink,避免持有失效引用 this.events = events; } @Override public void onCancel(Object arguments) { this.arguments = arguments; // 取消监听时清空sink this.events = null; } @Override public void sendCard(ICard iCard) { // 先判空,再加异常捕获,避免极端场景下sink刚好失效 if (this.events != null) { try { String cardString = JSON.toJSONString(iCard); this.events.success(cardString); } catch (Exception e) { // 出现异常说明sink已失效,直接清空 this.events = null; } } } }
如果是多引擎场景,每次Flutter引擎初始化时要重新注册EventChannel,不要复用全局的ICardEventCallHandler实例。
2. Flutter Dart端修改
给EventChannel的订阅增加取消逻辑,和业务生命周期绑定:
import 'package:flutter/services.dart'; class ChannelHelper{ static const eventChannel = const EventChannel("com.card/event"); // 保存订阅实例,用于取消监听 static StreamSubscription? _cardSubscription; static void handleReadCard(void onData(dynamic event)){ // 先取消旧的订阅,避免重复监听 cancelCardListener(); LoggerPrinter.info("listening card."); _cardSubscription = eventChannel.receiveBroadcastStream().listen(onData); } // 提供取消监听的方法,在页面dispose、APP退后台不需要监听时调用 static void cancelCardListener() { _cardSubscription?.cancel(); _cardSubscription = null; } }
如果是全局监听,可以在APP的initState中调用handleReadCard,在APP退到后台不需要读卡时调用cancelCardListener,回到前台时重新注册监听即可。
内容的提问来源于stack exchange,提问作者hehe
相关产品推荐
相关产品推荐

