Flutter中ReceivePort无法监听flutter_downloader回调数据问题
Flutter Downloader回调数据无法通过ReceivePort接收的问题
问题描述
使用flutter_downloader包时,ReceivePort的listen方法无法接收下载任务的回调数据。已按照要求仅传递原始对象(将DownloadTaskStatus转为value),但问题仍未解决。日志中仅能看到回调方法的输出,listen方法内的日志无输出。
代码示例
final ReceivePort _receivePort = ReceivePort(); int? status; int? progress; String? id; @override void initState() { IsolateNameServer.registerPortWithName(_receivePort.sendPort, 'downloader_send_port'); _receivePort.listen( (data) async { Logger().e('task listen data: $data'); // 此处无日志输出 // setState(() { // id = data[0]; // status = data[1]; // progress = data[2]; // }); }, ); FlutterDownloader.registerCallback(downloadCallback); super.initState(); } @override void dispose() { IsolateNameServer.removePortNameMapping('downloader_send_port'); } @pragma('vm:entry-point') static void downloadCallback(String id, DownloadTaskStatus status, int progress) { final SendPort? send = IsolateNameServer.lookupPortByName('downloader_send_port'); Logger().e('task send id: $id'); Logger().e('task send status: ${status.value}'); Logger().e('task send progress: $progress'); send?.send([id, status.value, progress]); }
日志输出
flutter: ^[[38;5;196m│ ⛔ task send id: io.myair.download.task.73570.1683533984.371354<…> flutter: ^[[38;5;196m│ ⛔ task send status: 1<…> flutter: ^[[38;5;196m│ ⛔ task send progress: 0<…> flutter: ^[[38;5;196m│ ⛔ task send id: io.myair.download.task.73570.1683533984.371354<…> flutter: ^[[38;5;196m│ ⛔ task send status: 3<…> flutter: ^[[38;5;196m│ ⛔ task send progress: 100<…>
解决方案
1. 修正initState执行顺序
Flutter要求initState方法必须首先调用super.initState(),否则会导致生命周期异常,影响端口注册和监听的有效性。修改后的initState如下:
@override void initState() { super.initState(); // 移至最开头 IsolateNameServer.registerPortWithName(_receivePort.sendPort, 'downloader_send_port'); _receivePort.listen( (data) async { Logger().e('task listen data: $data'); setState(() { id = data[0]; status = data[1]; progress = data[2]; }); }, ); FlutterDownloader.registerCallback(downloadCallback); }
2. 完善dispose资源回收
在dispose中关闭ReceivePort,避免资源泄漏,同时确保端口映射被正确移除:
@override void dispose() { IsolateNameServer.removePortNameMapping('downloader_send_port'); _receivePort.close(); // 添加端口关闭逻辑 super.dispose(); }
3. 确保FlutterDownloader完成初始化
在main函数中调用FlutterDownloader.initialize(),这是包的必要初始化步骤:
void main() async { WidgetsFlutterBinding.ensureInitialized(); await FlutterDownloader.initialize(debug: true); // debug模式可开启日志 runApp(const MyApp()); }
4. 排查端口查找失败情况
在回调函数中增加日志判断SendPort是否存在,确认端口注册是否成功:
@pragma('vm:entry-point') static void downloadCallback(String id, DownloadTaskStatus status, int progress) { final SendPort? send = IsolateNameServer.lookupPortByName('downloader_send_port'); if (send == null) { Logger().e('SendPort未找到,无法传递回调数据'); return; } Logger().e('task send id: $id'); Logger().e('task send status: ${status.value}'); Logger().e('task send progress: $progress'); send.send([id, status.value, progress]); }
5. Release模式兼容处理
如果在Release模式运行,确保downloadCallback不会被编译器混淆:
- 保留
@pragma('vm:entry-point')注解,该注解会告诉编译器不要混淆此方法 - 若开启了代码混淆,在
pubspec.yaml中确保相关代码不被混淆(或直接关闭混淆测试)
内容的提问来源于stack exchange,提问作者Veronika Haichenko
相关产品推荐
相关产品推荐

