兄弟们,今天写 Flutter 又踩坑了
今天本来想安安静静写个功能,就是把一些数据写到手机本地文件里。结果 App 直接给我闪退,后台报了这么一长串红字:
E/flutter (19945):
E/flutter (19945): [ERROR:flutter/runtime/dart_vm_initializer.cc(40)] Unhandled Exception: Bad state: StreamSink is bound to a stream
E/flutter (19945): #0 _StreamSinkImpl.close (dart:io/io_sink.dart:204:7)
E/flutter (19945): #1 _LocalFilePageState.reader.<anonymous closure> (package:firest/page/more/local_page/local_page.dart:90:14)
... (省略一堆看不懂的)
Bad state: StreamSink is bound to a stream
,这玩意儿直接给我整蒙了。“流处理器已经绑定到一个流”?这是啥意思?我寻思我也没对它做啥奇怪的操作啊。
问题出在哪?
查了半天资料,又结合官方的说法,大概搞明白了。
这个错误的意思是,你试图关闭一个 StreamSink
(可以理解为一个“数据写入的口子”),但它当时正处于一个“工作状态”或者“状态不对”,不允许你关。
通常是我们手动操作 IOSink
(StreamSink
的一种)时,代码写得太复杂,或者在某个异步操作之后,它的状态已经不是我们想的那样了,这时候强行 close()
就会触发这个异常。
我之前的代码大概是这样的,想手动控制流的写入和关闭:
// 导致问题的代码(示意)
Future<void> problematicWrite(File file, Stream<List<int>> dataStream) async {
var sink = file.openWrite(); // 1. 打开一个写入流
// 2. 把一个数据流(dataStream)的内容写进去
await sink.addStream(dataStream);
// ... 可能还有其他一些异步操作 ...
// 3. 在这里关闭,但此时 sink 的状态可能已经因为它内部的工作流而变得复杂
await sink.close(); // <--- 罪魁祸首就在这!
}
正确的姿势是啥?
后来发现,其实是我想复杂了。Flutter 对于文件读写这种常用操作,早就提供了更简单、更安全的“一条龙”方法。
核心就是:别自己手动管 IOSink
的打开和关闭了!
直接用 File
对象自带的 writeAsBytes()
方法,它会帮你搞定所有事:打开文件 -> 写入数据 -> 关闭文件。全程自动化,根本不给你犯错的机会。
修改后的代码就清爽多了:
import 'dart:io';
import 'dart:typed_data';
// 正确的姿势
Future<void> saveFile(String filePath, Uint8List data) async {
try {
var file = File(filePath);
// 就这一行代码,搞定!
// 它内部会处理好打开、写入、关闭的所有流程
await file.writeAsBytes(data);
print('文件写入成功!');
} catch (e) {
print('写入文件时出错了: $e');
}
}
总结一下
所以,下次再遇到 Bad state: StreamSink is bound to a stream
这个错,别慌。
99% 的可能性是你手动操作 IOSink
或 StreamSink
时,在某个环节把它状态搞乱了。
最省事的解决办法就是:
放弃手动管理流,直接用
file.writeAsBytes()
(写字节) 或者file.writeAsString()
(写字符串)。
让官方封装好的方法帮你处理这些复杂的流操作,不仅代码更简洁,还更安全。
行了,今天的水文就到这,希望能帮到同样踩坑的兄弟。