You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter本地5000+Txt文件多词搜索优化:解决卡顿并实现进度显示

Flutter 本地大数量文本搜索优化:避免冻结并显示进度条

问题背景

本地存储5000+每个至少15行内容的.txt文件,已实现多词全量搜索功能,但搜索时App会冻结直至流程结束,需要优化实现搜索时显示进度条且无UI阻塞。

现有代码问题分析

  1. 主线程阻塞:所有搜索、正则匹配、排序操作都在UI线程执行,密集计算直接导致App冻结。
  2. 无进度反馈:没有任何进度更新机制,用户无法感知搜索状态。
  3. 重复计算冗余:多次重复调用文本归一化和正则匹配,额外消耗性能。

优化方案

核心思路是将密集计算移至后台线程(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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 20:15:33