扫描服务架构梳理:PC端与移动端扫描服务完整技术方案

扫描服务架构梳理:PC端与移动端扫描服务完整技术方案

摘要

本文档详细梳理了芯图相册PC端和移动端的扫描服务架构,涵盖状态管理、进度更新、数据读写、界面刷新等核心机制。

核心架构差异

PC端:纯JS实现,Electron主进程执行,无后台限制,数据刷新直接执行。

移动端:三层架构(前台服务 + 原生层 + JS层),使用前台服务和WakeLock确保后台执行,数据刷新采用防抖机制(500ms)。

关键特性

1. 统一接口:两端都使用 GalleryScannerServiceUnifiedDataService 统一接口

2. 进度回调:通过 onProgress 回调更新UI,支持国际化消息

3. 缓存机制:使用内存缓存(精简信息)优化性能,按需加载详细信息

4. 多维度分类:支持11个分类维度(AI分类、城市、颜色、目录、格式、分辨率、方向、ISO、光圈、快门、焦距)

5. 流水线架构:移动端位置信息补全采用流水线并行处理,平衡CPU和IO任务

数据流程

PC端:文件系统 → JS层扫描 → IndexedDB → 缓存 → 界面

移动端:MediaStore → 原生层扫描 → SQLite → JS层处理 → 缓存 → 界面

---

目录

1. PC端扫描服务架构

2. 移动端扫描服务架构

3. 关键机制对比

---

PC端扫描服务架构

1. 扫描状态管理

#### 1.1 状态变量

  • 界面层状态 (HomeScreen.desktop.js):
  • isScanning: React state,控制扫描UI状态
  • globalMessage: React state,显示扫描进度消息
  • window.isScanning: 全局变量,供其他页面检查扫描状态
  • 服务层状态 (GalleryScannerService.js):
  • this.isScanning: 服务内部扫描状态标志
  • this.isInitialized: 服务初始化标志
  • this.onProgress: 进度回调函数引用

#### 1.2 状态流转

2. 进度消息更新机制

#### 2.1 进度消息生成流程

#### 2.2 进度消息去重

  • PC端使用 lastProgressMessage 键值去重
  • 格式:${stage}_${totalFoundThisPhase}_${processedThisPhase}
  • 相似度检测阶段不过滤(允许频繁更新)

#### 2.3 进度阶段定义

  • initializing: 初始化扫描
  • directory_scanning: 目录扫描
  • file_comparison: 文件比对
  • screenshot_detection: 截图检测
  • cache_checking: 缓存检查
  • remote_inference: 远程推理
  • local_inference: 本地推理
  • similarity_detection: 相似度检测
  • location_enrichment: 位置信息补全
  • completed: 扫描完成

3. 数据读写机制

#### 3.1 数据写入流程(按业务流程划分)

##### 3.1.1 基础扫描(JS层:从文件系统收集数据写入本地数据库)

##### 3.1.2 本地MobileNetV3推理(JS层:可选,辅助功能)

##### 3.1.3 AI分类(JS层:从后端API获取数据写入本地数据库)

##### 3.1.4 相似度检测(JS层:可选,可单独触发)

##### 3.1.5 城市信息补全(JS层:可选,可单独触发)

#### 3.2 数据缓存与界面数据交换机制

##### 3.2.1 缓存优先读取机制

##### 3.2.2 数据分级策略(精简信息 vs 详细信息)

##### 3.2.3 按需加载详细信息

##### 3.2.5 多维度分类支持机制

##### 3.2.4 统一数据服务接口

#### 3.3 数据刷新策略

  • 扫描完成时: progress.shouldRefresh === true 时刷新
  • 位置信息补全: 每处理50张图片触发一次刷新
  • 相似度检测: 每检测完一个相似组触发刷新
  • 防抖机制: PC端无防抖,直接刷新

4. 界面数据刷新

#### 4.1 刷新触发点

#### 4.2 刷新内容

  • 分类统计 (loadCategories())
  • 城市统计 (loadCities())
  • 相似组统计 (loadSimilarityGroups())
  • 最近照片 (loadRecentImages())
  • 其他分类数据(颜色、目录、格式等)

---

移动端扫描服务架构

1. 扫描状态管理

#### 1.1 状态变量

  • 界面层状态 (HomeScreen.mobile.js):
  • isScanning: React state,控制扫描UI状态
  • globalMessage: React state,显示扫描进度消息
  • window.isScanning: 全局变量,供其他页面检查扫描状态
  • JS服务层状态 (GalleryScannerService.android.js):
  • this.isScanning: JS层扫描状态标志
  • this.currentScanId: 当前扫描任务ID
  • this.onProgress: 进度回调函数引用
  • this.eventEmitter: 原生事件监听器
  • 原生层状态 (GalleryScanService.java):
  • 扫描任务状态(运行中/已完成/已取消)
  • 扫描进度统计(已处理/总数)

#### 1.2 状态流转

2. 进度消息更新机制

#### 2.1 进度消息生成流程(三层架构)

#### 2.2 前台服务通知更新

  • 服务启动: ScanService.startScanService() 启动前台服务
  • 进度更新: ScanService.updateProgress(message, processed, total, title)
  • 服务停止: ScanService.stopScanService() 停止前台服务
  • 心跳机制: 每10秒更新一次通知,保持服务活跃

#### 2.3 进度消息去重

  • 移动端不移除去重逻辑,允许所有进度更新通过
  • 原因:原生层已经控制更新频率,JS层不需要再次过滤

3. 数据读写机制

#### 3.1 原生层数据写入

##### 3.1.1 基础扫描流程(独立流程)

##### 3.1.2 AI分类流程(独立流程,用户手动触发)

#### 3.2 JS层数据读取

  • 与PC端相同,使用 UnifiedDataService 统一接口
  • 支持缓存机制,减少数据库查询

#### 3.3 数据刷新策略

  • 防抖机制: 使用 loadAllDataDebounced() 防抖刷新(500ms)
  • 刷新触发:
  • 扫描完成时:清除防抖定时器,延迟600ms后刷新
  • 位置信息补全:每处理50张图片触发防抖刷新
  • 相似度检测:每检测完一个相似组触发防抖刷新

4. 界面数据刷新

#### 4.1 刷新触发点

#### 4.2 防抖机制

6. 移动层架构(三层)

#### 6.1 前台服务层 (ScanForegroundService.java)

  • 职责: 保持应用在后台运行时继续扫描
  • 机制:
  • 前台通知显示扫描进度
  • WakeLock防止CPU休眠
  • 心跳机制(10秒)保持服务活跃
  • 生命周期:
  • START_SCAN: 启动服务,获取WakeLock
  • UPDATE_PROGRESS: 更新通知内容
  • STOP_SCAN: 停止服务,释放WakeLock

#### 6.2 原生层 (GalleryScanService.java)

  • 职责: 执行实际的扫描和分类任务
  • 机制:
  • 独立后台线程执行扫描
  • MediaStore API扫描图片
  • SQLite数据库批量写入
  • MobileNetV3模型推理
  • 事件通信:
  • GalleryScanProgress: 进度事件
  • GalleryScanCompleted: 完成事件
  • GalleryScanError: 错误事件

#### 6.3 JS层 (GalleryScannerService.android.js)

  • 职责: 协调原生层和界面层
  • 机制:
  • 监听原生层事件
  • 处理进度数据国际化
  • 更新前台服务通知
  • 执行JS层后续处理(位置补全、相似度检测)
  • 桥接模块 (ScanServiceModule.java):
  • startScanService(): 启动前台服务
  • updateScanProgress(): 更新进度通知
  • stopScanService(): 停止前台服务

---

关键机制对比

1. 扫描状态管理

特性PC端移动端
状态变量isScanning, window.isScanningisScanning, window.isScanning
状态设置时机扫描开始时扫描开始时
状态清除时机扫描完成/失败时扫描完成/失败时
全局状态window.isScanningwindow.isScanning
### 2. 进度消息更新
特性PC端移动端
消息生成JS层 processProgressData()JS层 processProgressData()
消息去重有(基于消息键值)无(原生层已控制频率)
通知更新无(PC端不需要)有(前台服务通知)
更新频率每个阶段更新原生层控制频率
### 3. 数据读写
特性PC端移动端
扫描实现JS层实现原生层实现
数据库操作JS层直接操作原生层批量操作
数据刷新直接刷新防抖刷新(500ms)
刷新触发shouldRefresh 标志shouldRefresh 标志
### 4. 界面刷新
特性PC端移动端
刷新方式直接调用 loadData()防抖调用 loadAllDataDebounced()
刷新时机扫描完成、位置补全扫描完成、位置补全、相似度检测
防抖机制有(500ms延迟)
### 5. 新增分类处理
特性PC端移动端
AI分类实现JS层MobileNetV3原生层MobileNetV3
批量处理JS层批次处理原生层批次处理
后续处理位置补全、相似度检测位置补全、相似度检测
数据更新直接更新数据库原生层批量更新数据库
### 6. 后台执行能力
特性PC端移动端
后台扫描支持(Electron主进程)支持(前台服务)
进程保活不需要WakeLock + 前台服务
通知显示不需要前台服务通知
心跳机制不需要10秒心跳更新通知
---

总结

PC端特点

1. 纯JS实现: 所有扫描逻辑在JS层实现

2. 简单直接: 状态管理和进度更新简单直接

3. 无后台限制: Electron主进程可以长时间运行

4. 无防抖: 数据刷新直接执行,无需防抖

移动端特点

1. 三层架构: 前台服务 + 原生层 + JS层

2. 后台保活: 前台服务 + WakeLock确保后台执行

3. 防抖刷新: 避免频繁刷新影响性能

4. 原生性能: 原生层扫描和AI分类性能更好

共同点

1. 统一接口: 都使用 GalleryScannerService 统一接口

2. 进度回调: 都使用 onProgress 回调更新UI

3. 数据服务: 都使用 UnifiedDataService 统一数据接口

4. 状态管理: 都使用 isScanningwindow.isScanning 管理状态

← 返回日记列表