欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

一、前言

在游戏应用中,浏览历史可帮助用户快速找到最近查看的游戏。本文介绍如何在 Flutter HarmonyOS 应用中实现浏览历史,包括在线游戏和经典游戏的分类管理、自动记录、持久化存储等功能。

二、需求分析

2.1 功能需求

  • 自动记录:用户点击游戏时自动记录浏览历史
  • 分类管理:区分在线游戏和经典游戏
  • 历史查看:在个人中心查看浏览历史
  • 数据管理:支持删除单条、按类型清除、全部清除
  • 快速跳转:点击历史记录可快速打开游戏

2.2 技术挑战

  • 平台兼容性:HarmonyOS 上文件存储路径获取
  • 数据持久化:JSON 文件存储,兼容性处理
  • 去重机制:相同游戏只保留最新记录
  • 性能优化:限制记录数量,避免数据过大
  • 用户体验:空状态、加载状态、错误处理

三、架构设计

3.1 数据模型设计

  • 核心字段:游戏ID、标题、缩略图、游戏类型、浏览时间
  • JSON 序列化:支持持久化与恢复
  • 时间格式化:提供友好的时间显示(如“刚刚”“5分钟前”)

3.2 服务层设计

  • 存储管理:文件存储 + 内存缓存双重保障
  • 初始化流程:获取存储目录、加载历史数据
  • CRUD 操作:添加、查询、删除、清除
  • 分类查询:按游戏类型筛选

3.3 UI 层设计

  • Tab 切换:在线游戏/经典游戏两个标签页
  • 列表展示:卡片式布局,显示缩略图、标题、时间
  • 交互功能:点击跳转、单条删除、批量清除
  • 状态管理:加载、空状态、错误处理

四、核心实现

4.1 数据模型实现

4.1.1 BrowseHistory 模型定义
class BrowseHistory {
  final int gameId;           // 游戏ID,用于唯一标识
  final String gameTitle;     // 游戏标题,用于显示
  final String thumbnail;     // 缩略图URL,用于展示
  final String gameType;      // 游戏类型:'online' 或 'classic'
  final DateTime browseTime;  // 浏览时间,用于排序和显示
  
  // 构造函数和JSON序列化方法
}
4.1.2 时间格式化方法
String get formattedBrowseTime {
  final now = DateTime.now();
  final difference = now.difference(browseTime);
  
  if (difference.inDays > 0) {
    return '${difference.inDays}天前';
  } else if (difference.inHours > 0) {
    return '${difference.inHours}小时前';
  } else if (difference.inMinutes > 0) {
    return '${difference.inMinutes}分钟前';
  } else {
    return '刚刚';
  }
}

4.2 服务层实现

4.2.1 存储初始化
  • Platform Channel 获取目录:优先通过 MethodChannel 获取 HarmonyOS 应用数据目录
  • 路径回退机制:失败时尝试常见路径(/data/storage/el2/base/haps 等)
  • 临时目录兜底:最终回退到系统临时目录
  • 自动加载历史:初始化时从文件加载已有数据
4.2.2 添加浏览历史
static Future<void> addHistory(BrowseHistory history) async {
  // 1. 去重:移除相同游戏的旧记录
  _memoryCache.removeWhere((h) => 
    h.gameId == history.gameId && h.gameType == history.gameType
  );
  
  // 2. 添加到列表开头(最新在前)
  _memoryCache.insert(0, history);
  
  // 3. 限制数量:最多保存100条记录
  if (_memoryCache.length > 100) {
    _memoryCache.removeRange(100, _memoryCache.length);
  }
  
  // 4. 持久化保存
  await _saveToFile();
}

要点:

  • 去重:相同游戏只保留最新记录
  • 排序:新记录插入到列表开头
  • 限制:最多100条,避免数据过大
  • 持久化:立即保存到文件
4.2.3 分类查询方法
  • getAllHistory():获取所有浏览历史
  • getOnlineGameHistory():筛选在线游戏(gameType == 'online'
  • getClassicGameHistory():筛选经典游戏(gameType == 'classic'
    在这里插入图片描述
    在这里插入图片描述
4.2.4 清除功能实现
  • clearAllHistory():清空内存缓存并删除文件
  • clearOnlineGameHistory():只清除在线游戏记录
  • clearClassicGameHistory():只清除经典游戏记录
  • deleteHistory():删除单条记录(通过ID、类型、时间匹配)

4.3 UI 层实现

4.3.1 Tab 切换设计
TabBar(
  controller: _tabController,
  tabs: const [
    Tab(icon: Icon(Icons.gamepad), text: '在线游戏'),
    Tab(icon: Icon(Icons.stars), text: '经典游戏'),
  ],
)
  • 使用 TabController 管理切换
  • 两个标签页分别显示不同类型的历史
  • 图标区分:游戏手柄(在线)、星星(经典)
4.3.2 历史记录项构建
  • 缩略图展示:网络图片加载,失败时显示占位图标
  • 信息展示:游戏标题、浏览时间、类型标签
  • 交互按钮:删除按钮,支持单条删除
  • 点击跳转:点击卡片跳转到对应游戏
4.3.3 点击跳转逻辑

在线游戏:

  • 通过游戏ID查找游戏信息
  • 尝试打开游戏官网
  • 失败时显示URL对话框,支持复制链接

经典游戏:

  • 根据游戏标题判断(如“2048”)
  • 跳转到对应游戏页面
  • 未实现游戏显示开发中提示
4.3.4 清除功能实现
  • 清除按钮:AppBar 右上角删除图标
  • 智能清除:根据当前Tab清除对应类型的历史
  • 确认对话框:危险操作二次确认
  • 空状态处理:无历史时显示提示

4.4 集成实现

4.4.1 在线游戏列表集成
Future<void> _openGameWebsite(Game game) async {
  // 记录浏览历史
  try {
    final history = BrowseHistory(
      gameId: game.id,
      gameTitle: game.title,
      thumbnail: game.thumbnail,
      gameType: 'online',
      browseTime: DateTime.now(),
    );
    await BrowseHistoryService.addHistory(history);
  } catch (e) {
    debugPrint('记录浏览历史失败: $e');
  }
  
  // 继续打开游戏官网的逻辑...
}
  • _openGameWebsite 方法开头记录历史
  • 使用 try-catch 确保记录失败不影响主流程
  • 记录时机:用户点击游戏时立即记录
4.4.2 经典游戏列表集成
onTap: () async {
  // 记录浏览历史
  try {
    final history = BrowseHistory(
      gameId: game.id,
      gameTitle: game.title,
      thumbnail: game.thumbnail,
      gameType: 'classic',
      browseTime: DateTime.now(),
    );
    await BrowseHistoryService.addHistory(history);
  } catch (e) {
    debugPrint('记录浏览历史失败: $e');
  }
  
  // 继续游戏跳转逻辑...
}
  • 在游戏点击事件中记录历史
  • 游戏类型设置为 'classic'
  • 异步处理,不阻塞UI
4.4.3 主应用初始化
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  // 初始化浏览历史服务
  try {
    await BrowseHistoryService.initialize();
  } catch (e) {
    debugPrint('初始化浏览历史服务失败: $e');
  }
  
  runApp(const MyApp());
}
  • 应用启动时初始化服务
  • 错误处理:初始化失败不影响应用启动
  • 确保存储目录准备就绪
4.4.4 个人中心集成
_buildMenuTile(
  icon: Icons.history,
  title: '浏览历史',
  subtitle: '查看浏览过的游戏',
  onTap: () {
    Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => const BrowseHistoryPage(),
      ),
    );
  },
)
  • 导航跳转:点击后导航到浏览历史页面
  • 用户体验:清晰的入口和说明

五、技术亮点

5.1 自动去重机制

  • 去重策略:相同游戏ID + 相同类型视为重复
  • 更新方式:移除旧记录,插入新记录到开头
  • 优势:避免重复,保持最新记录在前

5.2 分类管理

  • 类型标识:gameType 字段区分在线/经典
  • 分类查询:提供按类型查询方法
  • UI 展示:Tab 切换,清晰分类
  • 独立清除:支持按类型清除

5.3 持久化存储

  • 文件存储:JSON 文件持久化
  • 平台兼容:HarmonyOS 路径获取与回退
  • 双重保障:文件存储 + 内存缓存
  • 自动加载:启动时自动加载历史数据

5.4 用户体验优化

  • 时间显示:友好的相对时间(“刚刚”“5分钟前”)
  • 空状态:无历史时显示提示
  • 加载状态:加载时显示进度指示器
  • 错误处理:操作失败时显示错误提示
  • 下拉刷新:支持下拉刷新历史数据
  • 删除反馈:删除操作后显示成功提示

5.5 性能优化

  • 数量限制:最多保存100条记录
  • 内存缓存:减少文件读写
  • 异步处理:不阻塞UI线程
  • 按需加载:只在需要时加载数据

六、总结

6.1 实现成果

  • 完整的浏览历史功能:自动记录、分类管理、持久化存储
  • 良好的用户体验:清晰的UI、流畅的交互、友好的提示
  • 健壮的代码:完善的错误处理、平台兼容性处理

6.2 扩展方向

  • 搜索功能:在历史记录中搜索游戏
  • 排序功能:按时间、标题等排序
  • 统计功能:显示浏览次数、最常浏览的游戏
  • 同步功能:云端同步浏览历史

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐