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

从API向IsarDB插入955条数据时应用卡顿,求排查优化方案

问题分析与解决方案

核心问题根源

  1. 同步数据库操作阻塞主线程
    你使用了writeTxnSync、putAllSync这类同步方法,它们会直接占用Flutter的主线程(UI线程)执行IO操作,导致界面完全冻结,直到数据库写入完成。

  2. 循环内重复且冗余的数据库写入
    遍历API返回数据的循环中,每添加一个Client就执行一次数据库写入,甚至在if分支内外重复执行两次写入,产生大量不必要的IO操作,进一步加剧主线程阻塞。

  3. 本地数据判断逻辑错误
    isarClients是Future对象,你在循环内反复通过await isarClients.then(...)判断本地数据是否为空,不仅逻辑冗余,还会多次等待同一个Future,浪费系统资源。


修正后的代码实现

Future<List<Client>> getAllClientsBySeller({int limit = 10, int offset = 0}) async {
  final isar = await db;
  // 提前获取本地分页数据,避免重复await
  final localClients = await isar.clients.where().offset(offset).limit(limit).findAll();

  // 本地已有数据则直接返回(可根据业务需求调整是否强制同步)
  if (localClients.isNotEmpty) {
    return localClients;
  }

  try {
    // 从API拉取全量数据
    final response = await dio.get('/clients/seller?limit=1500&offset=0');
    final List<Client> clients = [];

    // 一次性完成所有数据转换
    for (final client in response.data ?? []) {
      clients.add(ClientMapper.jsonToEntity(client));
    }

    // 使用异步事务批量写入,避免阻塞主线程
    await isar.writeTxn(() async {
      await isar.clients.putAll(clients);
    });

    // 写入完成后返回分页后的本地数据
    return await isar.clients.where().offset(offset).limit(limit).findAll();
  } catch (e) {
    throw CustomError('Error: ($e)');
  }
}

额外优化建议

  • 增量同步替代全量拉取:如果业务允许,不要每次拉取1500条全量数据,可以根据lastUpdatedAt等字段做增量同步,减少数据处理量。
  • Riverpod异步状态管理:将clientsProvider改为异步Provider,在UI层优雅处理加载、错误、数据状态,避免界面无响应:
    final clientsProvider = AsyncNotifierProvider<ClientsNotifier, List<Client>>(() {
      return ClientsNotifier();
    });
    
    class ClientsNotifier extends AsyncNotifier<List<Client>> {
      @override
      Future<List<Client>> build() async {
        return ref.read(clientRepository).getAllClientsBySeller();
      }
    
      // 手动触发同步方法
      Future<void> syncClients() async {
        state = const AsyncLoading();
        try {
          final clients = await ref.read(clientRepository).getAllClientsBySeller();
          state = AsyncData(clients);
        } catch (e) {
          state = AsyncError(e, StackTrace.current);
        }
      }
    }
    
    页面监听示例:
    final clientsAsync = ref.watch(clientsProvider);
    clientsAsync.when(
      loading: () => const CircularProgressIndicator(),
      error: (e, st) => Text('加载失败: $e'),
      data: (clients) => // 渲染客户列表组件
    );
    

内容的提问来源于stack exchange,提问作者Rudy Rosa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 22:53:13