Flutter中使用StreamBuilder展示Algolia搜索结果无内容求助
问题:Flutter中调用Algolia搜索后StreamBuilder无结果显示
我是Flutter新手,正在开发一个在TextField输入文本并调用Algolia进行搜索的程序。输入文本后Algolia能正常处理,但屏幕上没有返回任何结果。我怀疑是否是使用StreamBuilder导致的问题(换成FutureBuilder会不会更好?),希望能得到帮助。
目前没有报错信息,但StreamBuilder中的snapshot为null,不过Future中的hits能正常打印出长度。
代码示例
import 'dart:async'; import 'package:algolia/algolia.dart'; import 'package:flutter/material.dart'; import '../../main.dart'; class Application { static final Algolia algolia = Algolia.init( applicationId: '78CZVABC2W', apiKey: 'c2377e7faad9a408d5867b849f25fae4', ); } class Search extends StatefulWidget { @override _SearchState createState() => _SearchState(); } class _SearchState extends State<Search> { StreamController<List<AlgoliaObjectSnapshot>> searchController = StreamController(); Future searchFireStore(word) async { Algolia algolia = Application.algolia; AlgoliaQuery query = algolia.instance.index("rigaku_index").query(word); AlgoliaQuerySnapshot snap = await query.getObjects(); List<AlgoliaObjectSnapshot> hits = snap.hits; searchController.add(hits); print(hits.length); } final _algilia = Application.algolia; @override void dispose() { searchController.close(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: SearchItems(), backgroundColor: Colors.white, ), body: Column( children: <Widget>[ Expanded( child: StreamBuilder( stream: searchController.stream, builder: (context,AsyncSnapshot snapshot) { if (snapshot.hasData) { return ListView.builder( itemCount: snapshot.data.length, itemBuilder: (context, index) { return Text((snapshot.data[index].data['zyugyoumei'])); }, ); } else { return Center( child: Text("No Data"), ); } }, ), ) ], ), ); } } class SearchItems extends StatefulWidget { @override _SearchItemsState createState() => _SearchItemsState(); } class _SearchItemsState extends State<SearchItems> { String searchWord = ""; @override Widget build(BuildContext context) { return TextField( decoration: const InputDecoration( hintText: '検索', ), controller: TextEditingController(text: searchWord), onChanged: (String text) { setState(() { searchWord = text; }); }, onSubmitted: (searchWord) =>_SearchState().searchFireStore(searchWord)); } }
解决方案
核心问题定位
你在SearchItems的onSubmitted里直接创建了_SearchState的新实例来调用searchFireStore,但这个新实例和页面上正在运行的_SearchState完全不是同一个对象。新实例的searchController发送的数据,页面上绑定的StreamBuilder根本接收不到,这就是为什么hits能打印但UI没更新的原因。
修复步骤
- 给
SearchItems添加搜索回调
修改SearchItems,通过回调函数将搜索事件传递给父组件的_SearchState,而不是创建新的State实例:
class SearchItems extends StatefulWidget { // 定义搜索回调 final Function(String) onSearchSubmitted; // 构造函数接收回调 const SearchItems({required this.onSearchSubmitted, Key? key}) : super(key: key); @override _SearchItemsState createState() => _SearchItemsState(); }
然后在TextField的onSubmitted中调用这个回调:
onSubmitted: (searchWord) => widget.onSearchSubmitted(searchWord)
- 在父组件中传递回调
在Search的build方法里,将searchFireStore方法作为回调传递给SearchItems:
appBar: AppBar( title: SearchItems(onSearchSubmitted: searchFireStore), backgroundColor: Colors.white, ),
- 优化StreamBuilder的状态处理(可选)
为了提升用户体验,可以完善StreamBuilder的状态判断,处理加载中和空数据的情况:
builder: (context, AsyncSnapshot snapshot) { // 处理加载状态 if (snapshot.connectionState == ConnectionState.waiting) { return Center(child: CircularProgressIndicator()); } // 有数据且不为空时展示列表 if (snapshot.hasData && snapshot.data.isNotEmpty) { return ListView.builder( itemCount: snapshot.data.length, itemBuilder: (context, index) { // 处理字段可能为null的情况 return Text(snapshot.data[index].data['zyugyoumei'] ?? '无名称'); }, ); } else { return Center( child: Text("暂无搜索结果"), ); } }
StreamBuilder vs FutureBuilder的选择
- StreamBuilder:适合实时搜索场景(比如输入文字时自动触发搜索),可以多次向流中发送数据更新UI,你的场景用它完全没问题,之前的问题和它无关。
- FutureBuilder:适合单次搜索场景,每次提交搜索时需要更新State中的Future变量来触发UI刷新。如果只是提交时搜索一次,也可以用,但StreamBuilder在多次搜索的场景下更灵活。
内容的提问来源于stack exchange,提问作者gadgelogger
相关产品推荐
相关产品推荐

