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
相关产品推荐
相关产品推荐

