news 2026/9/12 18:13:35

用 Drift 实现 Repository 无缝接入本地缓存/数据库(SWR:先快后准)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用 Drift 实现 Repository 无缝接入本地缓存/数据库(SWR:先快后准)

1)依赖与初始化(pubspec 思路)

常见组合(按你项目选):

  • drift

  • drift_flutter(Flutter 项目推荐)

  • sqlite3_flutter_libs(iOS/Android 自带 sqlite)

  • path_provider+path

(版本你用最新即可)

2)Drift 表结构:profiles

关键字段:updatedAtMs用来做 TTL / 过期判断

import 'package:drift/drift.dart'; class Profiles extends Table { TextColumn get id => text()(); // 主键 TextColumn get name => text()(); TextColumn get avatar => text().nullable()(); IntColumn get updatedAtMs => integer()(); // 记录更新时间(毫秒) @override Set<Column> get primaryKey => {id}; }

3)Database 定义(AppDatabase)

使用drift_flutterNativeDatabase.createInBackground最省心。

import 'dart:io'; import 'package:drift/drift.dart'; import 'package:drift/drift.dart' as drift; import 'package:drift_flutter/drift_flutter.dart'; part 'app_database.g.dart'; @DriftDatabase(tables: [Profiles], daos: [ProfileDao]) class AppDatabase extends _$AppDatabase { AppDatabase() : super(_openConnection()); @override int get schemaVersion => 1; } LazyDatabase _openConnection() { return LazyDatabase(() async { return drift_flutter.openDatabase( name: 'app.db', native: const DriftNativeOptions( shareAcrossIsolates: true, ), ); }); }

说明:

  • part 'app_database.g.dart';需要 build_runner 生成

  • 文件名你可以按你工程改,比如db.dart

4)DAO:ProfileDao(watch + get + upsert)

Repository 最喜欢 DAO 提供这几个方法。

import 'package:drift/drift.dart'; import 'app_database.dart'; part 'profile_dao.g.dart'; @DriftAccessor(tables: [Profiles]) class ProfileDao extends DatabaseAccessor<AppDatabase> with _$ProfileDaoMixin { ProfileDao(AppDatabase db) : super(db); Stream<Profile?> watchProfile(String id) { return (select(profiles)..where((t) => t.id.equals(id))) .watchSingleOrNull(); } Future<Profile?> getProfile(String id) { return (select(profiles)..where((t) => t.id.equals(id))) .getSingleOrNull(); } Future<void> upsertProfile(ProfilesCompanion data) async { await into(profiles).insertOnConflictUpdate(data); } Future<void> deleteProfile(String id) async { await (delete(profiles)..where((t) => t.id.equals(id))).go(); } Future<void> clearAll() async { await delete(profiles).go(); } }

5)Domain Model + Mapper(别省略,后期维护靠它)

Domain Model

class ProfileModel { final String id; final String name; final String? avatar; ProfileModel({required this.id, required this.name, this.avatar}); }

Mapper:Drift Row ↔ Domain

Drift 的 row 类型叫Profile(与表名 Profiles 对应),下面示例:

import 'app_database.dart'; class ProfileMapper { static ProfileModel toModel(Profile row) { return ProfileModel( id: row.id, name: row.name, avatar: row.avatar, ); } static ProfilesCompanion toCompanion(ProfileModel m) { return ProfilesCompanion.insert( id: m.id, name: m.name, avatar: Value(m.avatar), updatedAtMs: DateTime.now().millisecondsSinceEpoch, ); } }

6)Remote API(Dio 获取网络数据)

接口层只负责“拿远端”,Repository 负责策略。

abstract class ProfileApi { Future<ProfileModel> fetchProfile(String id); }

7)Repository:DB 单一事实源 + refresh 回写(推荐)

7.1 watch:页面自动更新

class ProfileRepository { final ProfileApi api; final ProfileDao dao; ProfileRepository({required this.api, required this.dao}); Stream<ProfileModel?> watchProfile(String id) { return dao.watchProfile(id).map((row) => row == null ? null : ProfileMapper.toModel(row)); } Future<void> refreshProfile(String id) async { final remote = await api.fetchProfile(id); await dao.upsertProfile(ProfileMapper.toCompanion(remote)); } }

页面使用方式(思路):

  • UI 订阅watchProfile(id)→ 立即显示 DB 数据

  • 下拉刷新调用refreshProfile(id)→ 网络成功后写 DB → UI 自动更新

8)再加一层“TTL 过期策略”(先快后准 + 后台刷新)

如果你还想:DB 有旧数据先出,再判断过期自动刷新:

class CachePolicy { final Duration ttl; CachePolicy(this.ttl); bool isExpired(int updatedAtMs) { final age = DateTime.now().millisecondsSinceEpoch - updatedAtMs; return age > ttl.inMilliseconds; } } class ProfileRepositoryWithTtl { final ProfileApi api; final ProfileDao dao; final CachePolicy policy; ProfileRepositoryWithTtl({required this.api, required this.dao, required this.policy}); Stream<ProfileModel?> watchProfile(String id) { return dao.watchProfile(id).map((row) => row == null ? null : ProfileMapper.toModel(row)); } /// 页面进入时调用一次:如果过期就后台刷新 Future<void> refreshIfExpired(String id) async { final cached = await dao.getProfile(id); if (cached == null || policy.isExpired(cached.updatedAtMs)) { await refreshProfile(id); } } Future<void> refreshProfile(String id) async { final remote = await api.fetchProfile(id); await dao.upsertProfile(ProfileMapper.toCompanion(remote)); } }

9)和 401 自动刷新 Token 如何衔接?

完全无感:
Repository 调api.fetchProfile,Dio 层的 RefreshInterceptor 处理 401。
refresh 失败就触发全局onAuthExpired,UI 统一跳登录,Repository 不管。

10)你需要生成代码(Drift 必做)

你有part '*.g.dart'的文件,需要 build:

flutter pub run build_runner build --delete-conflicting-outputs
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/9 19:01:09

一张Transformer-LSTM模型的结构图

一个典型的 Transformer-LSTM 混合模型 架构。这种设计结合了 Transformer 处理全局关联的能力和 LSTM 处理时序序列的优势。 1. 混合分层架构 (Hybrid Layering) 模型并没有简单地替换某个组件&#xff0c;而是采用串联堆叠的方式&#xff1a; 底层为 Transformer Encoder&…

作者头像 李华
网站建设 2026/9/2 23:49:20

AI智能体开发新范式:上下文工程,让大模型香不香,一试便知!

上下文工程是提示词工程的演进&#xff0c;关注如何在大模型有限注意力预算内筛选最优tokens。面对"上下文衰减"现象&#xff0c;需精心设计系统提示词、工具和示例&#xff0c;采用即时上下文和混合策略提升效率。长期任务可通过压缩、结构化笔记和多智能体架构突破…

作者头像 李华
网站建设 2026/8/28 17:47:34

计算机Java毕设实战-基于springboot的传媒公司传媒直播管理系统设计与实现基于SpringBoot+Vue的传媒公司主播招募管理系统【完整源码+LW+部署说明+演示视频,全bao一条龙等】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/8/28 17:47:00

茶颜悦色X北森|如何用AI面试官帮HR工作量直降90%!

作为新中式茶饮赛道的代表性品牌&#xff0c;茶颜悦色在持续践行“深耕大本营、稳步向外扩张”的战略过程中&#xff0c;门店总数已突破1000家。然而&#xff0c;随着规模的快速扩张&#xff0c;也面临着所有连锁企业共同的核心难题&#xff1a;如何高效、精准、大规模地招聘一…

作者头像 李华
网站建设 2026/9/10 1:04:33

系统找不到msrepl35.dll文件 无法运行程序 下载修复方法

在使用电脑系统时经常会出现丢失找不到某些文件的情况&#xff0c;由于很多常用软件都是采用 Microsoft Visual Studio 编写的&#xff0c;所以这类软件的运行需要依赖微软Visual C运行库&#xff0c;比如像 QQ、迅雷、Adobe 软件等等&#xff0c;如果没有安装VC运行库或者安装…

作者头像 李华
网站建设 2026/9/6 8:53:01

NVIDIA突破:超长推理链训练实现AI数学推理满分

这项由NVIDIA公司Wei Du、Shubham Toshniwal等研究团队开展的突破性研究于2025年12月发表在arXiv预印本平台&#xff0c;论文编号为arXiv:2512.15489v1。该研究构建了迄今为止最大规模的数学推理数据集Nemotron-Math&#xff0c;包含高达7500万条数学解题推理轨迹&#xff0c;让…

作者头像 李华