多次调用result.success致Flutter与Android交互崩溃问题求助
问题原因
你遇到的崩溃是因为MethodChannel的Result对象是单次请求-响应绑定的:每个invokeMethod调用对应一个唯一的Result,第一次调用result.success后,这个Result就会被标记为已完成,后续重复调用会触发Flutter端的断言错误,直接导致崩溃。你的场景需要多次推送回调数据,而MethodChannel是「单次请求-响应」模型,完全不匹配。
解决方案:改用EventChannel实现持续事件推送
EventChannel专门用于原生向Flutter推送持续的事件流,完美适配多次回调的场景,具体实现如下:
Android 原生侧实现
1. 注册EventChannel
在你的Flutter容器(Activity/Fragment)中初始化并注册EventChannel:
import io.flutter.plugin.common.EventChannel; import io.flutter.embedding.android.FlutterActivity; public class MainActivity extends FlutterActivity { private static final String EVENT_CHANNEL_NAME = "com.your.app/ui_events"; private MyEventsListener eventsListener; @Override public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) { super.configureFlutterEngine(flutterEngine); // 注册EventChannel处理事件流 new EventChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), EVENT_CHANNEL_NAME) .setStreamHandler(new EventChannel.StreamHandler() { @Override public void onListen(Object arguments, EventChannel.EventSink events) { // Flutter侧开始监听时,注册原生事件回调 eventsListener = new MyEventsListener() { @Override public void onEventDone(MyEvent myEvent) { if (myEvent != null) { JSONObject jsonObject = new JSONObject(); try { jsonObject.put("event_id", myEvent.eventID()); jsonObject.put("event_name", myEvent.eventName()); jsonObject.put("event_type", myEvent.eventType()); jsonObject.put("event_label", myEvent.eventLabel()); } catch (JSONException e) { e.printStackTrace(); events.error("JSON_PARSE_ERROR", "Failed to parse event data", null); return; } // 可多次调用events.success推送数据 events.success(jsonObject.toString()); } else { events.error("NULL_EVENT", "Could not fetch event data", null); } } }; EVENT.trackUIEvents(eventsListener); } @Override public void onCancel(Object arguments) { // Flutter侧取消监听时,移除原生回调避免内存泄漏 if (eventsListener != null) { // 请确保EVENT类提供移除监听的方法,比如: // EVENT.removeUIEventsListener(eventsListener); eventsListener = null; } } }); } }
Flutter 侧实现
1. 创建事件监听服务
import 'dart:convert'; import 'package:flutter/services.dart'; class UIEventsTracker { static const EventChannel _eventChannel = EventChannel('com.your.app/ui_events'); StreamSubscription? _subscription; // 返回事件流,供页面监听 Stream<Map<String, dynamic>> getEventStream() { return _eventChannel.receiveBroadcastStream().map((event) { final jsonString = event as String; return json.decode(jsonString) as Map<String, dynamic>; }); } // 停止监听(页面销毁时调用) void stopTracking() { _subscription?.cancel(); _subscription = null; } }
2. 在页面中使用监听
import 'package:flutter/material.dart'; class EventPage extends StatefulWidget { const EventPage({super.key}); @override State<EventPage> createState() => _EventPageState(); } class _EventPageState extends State<EventPage> { final UIEventsTracker _tracker = UIEventsTracker(); @override void initState() { super.initState(); // 开始监听事件 _tracker.getEventStream().listen((event) { // 每次收到原生推送的事件,都会触发这里 print('Received UI Event: $event'); // 处理事件数据、更新UI等操作 }, onError: (error) { print('Event Error: $error'); }); } @override void dispose() { // 页面销毁时停止监听,避免内存泄漏 _tracker.stopTracking(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('UI Events Tracker')), body: const Center(child: Text('Listening for UI events...')), ); } }
备选方案:保留MethodChannel(仅适合单次拉取)
如果你的场景不需要实时推送,只是每次主动拉取最新事件,可以修改MethodChannel实现,确保每个Result只被调用一次:
case MY_EVENTS: // 每次调用方法时创建独立的监听 MyEventsListener singleUseListener = new MyEventsListener() { @Override public void onEventDone(MyEvent myEvent) { // 回调后立即移除监听,避免重复触发 EVENT.removeUIEventsListener(this); if (myEvent != null) { JSONObject jsonObject = new JSONObject(); try { jsonObject.put("event_id", myEvent.eventID()); jsonObject.put("event_name", myEvent.eventName()); jsonObject.put("event_type", myEvent.eventType()); jsonObject.put("event_label", myEvent.eventLabel()); } catch (JSONException e) { e.printStackTrace(); result.error("0", "Parse failed", null); return; } result.success(jsonObject.toString()); } else { result.error("0", "No data", null); } } }; EVENT.trackUIEvents(singleUseListener); break;
这种方式下,Flutter侧每次调用trackUIEvents()只会获取一次最新事件,无法接收主动推送的更新。
内容的提问来源于stack exchange,提问作者Suresh B B
相关产品推荐
相关产品推荐

