Flutter本地5000+Txt文件多词搜索优化:解决卡顿并实现进度显示
Flutter 本地大数量文本搜索优化:避免冻结并显示进度条
问题背景
本地存储5000+每个至少15行内容的.txt文件,已实现多词全量搜索功能,但搜索时App会冻结直至流程结束,需要优化实现搜索时显示进度条且无UI阻塞。
现有代码问题分析
- 主线程阻塞:所有搜索、正则匹配、排序操作都在UI线程执行,密集计算直接导致App冻结。
- 无进度反馈:没有任何进度更新机制,用户无法感知搜索状态。
- 重复计算冗余:多次重复调用文本归一化和正则匹配,额外消耗性能。
优化方案
核心思路是将密集计算移至后台线程(Isolate),同时加入进度回调实时更新UI,减少重复计算提升效率。
1. 实现后台搜索Isolate
创建独立Isolate处理搜索逻辑,避免占用UI线程:
// Isolate参数封装类,用于传递数据和回调 class _IsolateSearchParams { final SendPort sendPort; final String searchText; final List<FatwaModel> fullFatawy; final void Function(int progress) updateProgress; _IsolateSearchParams({ required this.sendPort, required this.searchText, required this.fullFatawy, required this.updateProgress, }); } // Isolate入口函数,执行后台搜索 void _executeSearchInIsolate(_IsolateSearchParams params) { final searchText = params.searchText; final fullFatawy = params.fullFatawy; final updateProgress = params.updateProgress; if (searchText.isEmpty) { params.sendPort.send([]); return; } // 预处理搜索关键词,生成正则(只做一次) final normalisedSearch = RemoveExtinctionsAtWord().normalise(searchText).trim(); final validKeywords = normalisedSearch.split(' ').where((word) => word.length > 1).toList(); final searchRegExp = RegExp(validKeywords.join('|'), caseSensitive: false); final matchedResults = <FatwaModel>[]; final totalItems = fullFatawy.length; for (int i = 0; i < totalItems; i++) { final fatwa = fullFatawy[i]; // 预处理文本内容,避免重复计算 final targetBody = RegExp(r'(?<=:)(.*)').firstMatch(fatwa.fatwaBody)?.group(0) ?? ''; final normalisedBody = RemoveExtinctionsAtWord().normalise(targetBody); // 匹配检查 if (searchRegExp.hasMatch(normalisedBody)) { // 计算匹配次数,用于排序(建议给FatwaModel添加matchCount字段) final matchCount = searchRegExp.allMatches(normalisedBody).length; fatwa.matchCount = matchCount; matchedResults.add(fatwa); } // 每处理10条或最后一条时更新进度,减少UI刷新频率 if (i % 10 == 0 || i == totalItems - 1) { updateProgress(((i + 1) / totalItems * 100).round()); } } // 按匹配次数降序排序 matchedResults.sort((a, b) => b.matchCount.compareTo(a.matchCount)); // 发送结果回主线程 params.sendPort.send(matchedResults); } // 封装Isolate调用逻辑 Future<List<FatwaModel>> _runSearchInBackground( String searchText, List<FatwaModel> fullFatawy, void Function(int progress) onProgress, ) async { final receivePort = ReceivePort(); await Isolate.spawn( _executeSearchInIsolate, _IsolateSearchParams( sendPort: receivePort.sendPort, searchText: searchText, fullFatawy: fullFatawy, updateProgress: onProgress, ), ); return await receivePort.first; }
2. 修改原搜索方法,整合进度反馈
更新原方法,调用后台Isolate并通过状态管理发送进度:
// 假设使用Bloc进行状态管理,需提前定义SearchFatawyProgressState状态类 Future<List<FatwaModel>> searchFatawy(String searchText) async { if (searchText.isEmpty) return []; emit(SearchFatawyLoadingState()); searchFatawyTxt.clear(); final searchResults = await _runSearchInBackground( searchText, fullFatawy, (progress) { // 发送进度状态,UI层监听后更新进度条 emit(SearchFatawyProgressState(progress)); }, ); searchFatawyTxt.addAll(searchResults); emit(SearchFatawySuccessState()); return searchFatawyTxt; }
3. 配套调整
- FatwaModel扩展:添加
int? matchCount字段,用于存储匹配次数,方便排序。 - 状态类新增:创建
SearchFatawyProgressState(int progress),用于传递进度值给UI层。 - 序列化支持:确保FatwaModel可序列化(可使用
freezed或手动实现序列化逻辑),因为Isolate间传递数据需要支持序列化。
优化效果
- 无UI冻结:所有密集计算移至后台Isolate,UI线程保持响应。
- 实时进度反馈:用户可通过进度条直观看到搜索进度。
- 性能提升:预处理正则和文本,减少重复计算,搜索效率更高。
内容的提问来源于stack exchange,提问作者Ahmed Ragab
相关产品推荐
相关产品推荐

