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

Dart开发:如何避免重复从数据库实例化Tracker类?

问题:如何避免重复实例化Tracker类并重复查询数据库?

我在Dart中定义了一个可实例化的类:

class Tracker with ChangeNotifier {
  final double id;
  final String? trackerCode;
  final String? trackerName;
  final bool? isFavorite;
  final bool? isArchived;

  Tracker({
    required this.id,
    required this.trackerCode,
    required this.trackerName,
    required this.isFavorite,
    required this.isArchived,
  });
}

我通过数据库实例化该类:当用户访问主页时,会调用以下方法从数据库查询数据并创建该类的新实例:

static Future<List> selectAllDatabaseIsArchivedInformations() async {
    final Database database = await _databaseCheck();

    List trackersAvailable = await database.query("Correios",
        columns: [
          "id",
          "tracker_id",
          "tracker_code",
          "tracker_name",
          "is_favorite",
          "is_archived"
        ],
        where: "is_archived=1",
        whereArgs: ["0"]);

    for (var tracker in trackersAvailable) {
      Tracker(
        id: tracker['id'],
        trackerCode: tracker['tracker_code'],
        trackerName: tracker['tracker_name'],
        isFavorite: tracker['is_favorite'] == 1 ? true : false,
        isArchived: tracker['is_archived'] == 1 ? true : false,
      );
    }
    return trackersAvailable;
  }

现在的问题是:每次进入主页都会调用该方法重复查询数据库并实例化Tracker类,直到用户关闭应用。请问如何实现仅实例化一次该类,避免产生重复数据?


解决方案

1. 给数据库操作类添加结果缓存

在你的数据库工具类中添加静态缓存变量,存储已查询并实例化好的Tracker列表,后续请求直接复用缓存数据:

// 在数据库工具类中添加静态缓存变量
static List<Tracker>? _cachedArchivedTrackers;

static Future<List<Tracker>> selectAllDatabaseIsArchivedInformations() async {
    // 先检查缓存,存在则直接返回
    if (_cachedArchivedTrackers != null) {
      return _cachedArchivedTrackers!;
    }

    final Database database = await _databaseCheck();

    List trackersAvailable = await database.query("Correios",
        columns: [
          "id",
          "tracker_id",
          "tracker_code",
          "tracker_name",
          "is_favorite",
          "is_archived"
        ],
        where: "is_archived=1",
        whereArgs: ["0"]);

    // 实例化Tracker并收集到列表中
    List<Tracker> trackerList = [];
    for (var tracker in trackersAvailable) {
      trackerList.add(Tracker(
        id: tracker['id'],
        trackerCode: tracker['tracker_code'],
        trackerName: tracker['tracker_name'],
        isFavorite: tracker['is_favorite'] == 1 ? true : false,
        isArchived: tracker['is_archived'] == 1 ? true : false,
      ));
    }

    // 将实例化后的列表存入缓存
    _cachedArchivedTrackers = trackerList;
    return trackerList;
  }

注意:如果后续数据库中的归档数据有更新,需要手动清空缓存(比如执行_cachedArchivedTrackers = null;),这样下次查询时会重新拉取最新数据。

2. 结合状态管理(如Provider)统一管理数据

因为你的Tracker类混入了ChangeNotifier,可以用Provider全局管理数据,确保只加载一次:

  • 在应用启动或首次进入主页时,调用查询方法获取数据并存入Provider;
  • 主页直接从Provider中读取Tracker列表,无需重复调用数据库查询。

示例Provider代码:

class TrackerProvider with ChangeNotifier {
  List<Tracker> _archivedTrackers = [];
  bool _isLoaded = false;

  List<Tracker> get archivedTrackers => _archivedTrackers;

  Future<void> loadArchivedTrackers() async {
    if (_isLoaded) return;
    _archivedTrackers = await YourDatabaseClass.selectAllDatabaseIsArchivedInformations();
    _isLoaded = true;
    notifyListeners();
  }
}

主页中使用示例:

@override
void initState() {
  super.initState();
  // 仅首次加载数据
  Provider.of<TrackerProvider>(context, listen: false).loadArchivedTrackers();
}

@override
Widget build(BuildContext context) {
  final trackerProvider = Provider.of<TrackerProvider>(context);
  return ListView.builder(
    itemCount: trackerProvider.archivedTrackers.length,
    itemBuilder: (context, index) {
      final tracker = trackerProvider.archivedTrackers[index];
      return ListTile(title: Text(tracker.trackerName ?? ''));
    },
  );
}

额外修正:原代码的小问题

你原来的循环中仅实例化了Tracker,但没有收集这些实例,方法返回的是数据库查询的原始Map列表,并没有返回Tracker实例。上面的解决方案已修正该问题,确保实例化后的Tracker被正确存储和返回。


内容的提问来源于stack exchange,提问作者Ricardo Pereira

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 15:35:29