FutureBuilder无法实时展示新增列表元素,StreamBuilder适配报错求助
Flutter中FutureBuilder不更新、StreamBuilder类型不兼容的解决方法
问题原因
- FutureBuilder无法实时更新:FutureBuilder的
future参数只会在组件初始化时执行一次,新增数据后不会自动重新调用数据获取方法,所以列表不会刷新,必须手动触发重新执行future。 - StreamBuilder报错:StreamBuilder要求传入
Stream类型的数据源,但你传入的是Future,类型不匹配,所以抛出future is not a subtype of stream错误。
解决方案一:用StatefulWidget + setState刷新FutureBuilder
通过将数据获取的Future存在State中,新增数据后调用setState重新赋值Future,让FutureBuilder重新执行并刷新列表。
完整示例代码:
class NotePage extends StatefulWidget { const NotePage({super.key}); @override State<NotePage> createState() => _NotePageState(); } class _NotePageState extends State<NotePage> { late Future<List<Map>> _noteListFuture; @override void initState() { super.initState(); // 初始化加载数据 _noteListFuture = _getNoteList(); } // 获取笔记列表的方法 Future<List<Map>> _getNoteList() async { return await sq.ReadData('SELECT * FROM notes'); } // 刷新列表的方法,新增数据后调用 void _refreshNoteList() { setState(() { // 重新赋值Future,触发FutureBuilder刷新 _noteListFuture = _getNoteList(); }); } @override Widget build(BuildContext context) { return Scaffold( // 新增按钮示例,点击后执行新增逻辑并刷新 floatingActionButton: FloatingActionButton( onPressed: () async { // 这里执行新增笔记的数据库操作 // await sq.InsertData(...); // 新增完成后刷新列表 _refreshNoteList(); }, child: const Icon(Icons.add), ), body: FutureBuilder( future: _noteListFuture, builder: (context, AsyncSnapshot snapshot) { if (snapshot.hasData) { return ListView.builder( itemCount: snapshot.data.length, itemBuilder: (context, index) { return Container( height: 50, child: Card( child: Text('${snapshot.data[index]['note']}'), ), ); }, ); } else if (snapshot.hasError) { return Text('加载失败:${snapshot.error}'); } else { // 加载中状态 return const Center(child: CircularProgressIndicator()); } }, ), ); } }
解决方案二:将Future转为Stream,用StreamBuilder实现自动更新
通过StreamController手动管理数据流,每次数据变更时重新获取数据并发送到流中,StreamBuilder会自动监听流的变化刷新列表。
完整示例代码:
class NotePage extends StatefulWidget { const NotePage({super.key}); @override State<NotePage> createState() => _NotePageState(); } class _NotePageState extends State<NotePage> { late StreamController<List<Map>> _noteStreamController; @override void initState() { super.initState(); _noteStreamController = StreamController<List<Map>>(); // 初始加载数据到流中 _loadNoteList(); } // 加载数据并发送到流 Future<void> _loadNoteList() async { List<Map> noteList = await sq.ReadData('SELECT * FROM notes'); _noteStreamController.add(noteList); } @override void dispose() { // 页面销毁时关闭流,避免内存泄漏 _noteStreamController.close(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( floatingActionButton: FloatingActionButton( onPressed: () async { // 执行新增笔记操作 // await sq.InsertData(...); // 重新加载数据并发送到流 await _loadNoteList(); }, child: const Icon(Icons.add), ), body: StreamBuilder<List<Map>>( stream: _noteStreamController.stream, builder: (context, AsyncSnapshot<List<Map>> snapshot) { if (snapshot.hasData) { return ListView.builder( itemCount: snapshot.data!.length, itemBuilder: (context, index) { return Container( height: 50, child: Card( child: Text('${snapshot.data![index]['note']}'), ), ); }, ); } else if (snapshot.hasError) { return Text('加载失败:${snapshot.error}'); } else { return const Center(child: CircularProgressIndicator()); } }, ), ); } }
进阶方案:利用sqflite的监听功能(如果使用sqflite)
sqflite库支持通过watch方法监听查询结果的变化,自动返回Stream,无需手动触发刷新:
修改数据库查询方法为返回Stream:
Stream<List<Map>> watchNoteList() async* { Database? db = await getdb(); // 使用sqflite的watch方法,自动监听数据变化 yield* db!.rawQuery('SELECT * FROM notes').asStream(); }
然后直接在StreamBuilder中使用这个Stream:
StreamBuilder<List<Map>>( stream: sq.watchNoteList(), builder: (context, snapshot) { // 构建列表逻辑和之前一致 }, )
这样当数据库中的notes表数据变化时,Stream会自动发送新的列表数据,StreamBuilder会自动刷新列表。
内容的提问来源于stack exchange,提问作者meory
相关产品推荐
相关产品推荐

