Flutter Bloc搜索功能异常:搜索结果仅显示1条数据且存在问题
我帮你梳理了代码里的几个关键问题,这些应该就是导致搜索结果只显示1条和异常的核心原因:
1. Bloc事件处理逻辑冲突且存在错误
你在SearchNewsBloc里同时混用了Bloc 8.0+的新on<Event>绑定方式和旧版的mapEventToState方法,这会导致事件被重复处理;而且on<SearchNewsEvent>里的逻辑完全错误:
- 错误地判断
event is SearchNewsLoadingState(这是状态类,不是事件类) - 处理完事件后又主动
add(StartSearchNewsEvent),直接引发无限循环触发事件,数据被反复覆盖
修复方法:删除冗余的on<SearchNewsEvent>代码块,改用标准的on绑定逻辑(推荐),或者只保留mapEventToState。以下是标准的on绑定写法:
class SearchNewsBloc extends Bloc<SearchNewsEvent, SearchNewsState> { final NewsRepository newsRepository; SearchNewsBloc({required this.newsRepository}) : super(SearchNewsInitial()) { on<StartSearchNewsEvent>(_mapStartSearchToState); } Future<void> _mapStartSearchToState( StartSearchNewsEvent event, Emitter<SearchNewsState> emit, ) async { try { emit(SearchNewsLoadingState()); final articlesList = await newsRepository.searchNews(event.query); emit(SearchNewsLoadedState(articleList: articlesList)); } catch (e) { emit(SearchNewsErrorState(errorMessage: e.toString())); } } }
另外,构造函数里的initialState参数可以直接去掉,在super里传入SearchNewsInitial()即可。
2. Repository层API URL拼写错误
你把搜索接口的everything写成了eveything(少了一个字母r):
String url = "https://newsapi.org/v2/eveything?q=$query&apiKey=${NewsApiConstants.apiKey}";
这会导致请求返回错误,修正为:
String url = "https://newsapi.org/v2/everything?q=$query&apiKey=${NewsApiConstants.apiKey}";
3. 搜索结果页面布局限制导致显示不全
在SearchedNewsResult里,你给ListView.builder设置了NeverScrollableScrollPhysics和shrinkWrap: true,还套了两层Flexible,这会让列表无法正常滚动,甚至只渲染第一条数据就被截断。
修复方法:调整布局结构,用Expanded替代冗余的Flexible,让列表占据剩余空间并正常滚动:
@override Widget build(BuildContext context) { searchBloc.add(StartSearchNewsEvent(query: queryResult)); return Scaffold( appBar: customAppBar('Flash News', context), body: Column( children: [ Padding( padding: const EdgeInsets.all(15.0), child: Text(queryResult), ), Expanded( child: BlocBuilder<SearchNewsBloc, SearchNewsState>( builder: (context, state) { if (state is SearchNewsLoadingState) { return const Center(child: CircularProgressIndicator()); } else if (state is SearchNewsLoadedState) { return ListView.builder( itemCount: state.articleList.length, itemBuilder: (context, index) { final article = state.articleList[index]; return NewsCard( imgUrl: article.urlToImage ?? "", desc: article.description ?? "", title: article.title ?? "", content: article.content ?? "", postUrl: article.url ?? "", ); }, ); } else if (state is SearchNewsErrorState) { return Center(child: Text(state.errorMessage)); } else { return const Center(child: CircularProgressIndicator()); } }, ), ), ], ), ); }
另外,你之前给NewsCard传的imgUrl和postUrl是固定空字符串,要改成文章模型里的真实字段。
4. Equatable事件未正确重写props
你的SearchNewsEvent类里的props没有包含query字段,这会导致Equatable无法正确判断事件是否相同,可能引发重复触发或不触发事件的问题:
abstract class SearchNewsEvent extends Equatable { final String query; const SearchNewsEvent({required this.query}); @override List<Object?> get props => [query]; // 必须把query加入props列表 }
按照上面的方法修复后,应该就能正常显示所有搜索结果了。
内容的提问来源于stack exchange,提问作者sulli110




