HarmonyOS 小说查询应用:TaskPool 多线程 + 状态管理 V2 + Navigation 导航 全栈实战
效果

前言
本文完整介绍一个基于 HarmonyOS (API 23) 开发的小说文件查询应用。该应用综合运用了 TaskPool 多线程并发、State Management V2 状态管理和 Navigation 页面导航三大核心技术,实现了从文件初始化、关键词搜索、分类筛选、多维排序到详情查看的完整功能链路。
本文作为案例的总体介绍,帮助你快速了解应用的整体架构、功能效果和核心设计思路。如需深入了解某个模块的实现细节,请参考系列中的其他指南文档。
系列文档:
- 📘
@ohos.taskpool 使用指南— TaskPool API 详解与使用规范- 📗
小说文件查询案例指南— 基础查询功能的完整实现过程- 📙
Navigation 页面导航实现指南— 详情页跳转功能的添加步骤- 📕
本文— 案例总体介绍与效果展示
一、应用概述
1.1 应用定位
一个面向 HarmonyOS 开发者的教学级示范应用,通过一个实用的小型工具——小说文件查询器,展示如何在实际项目中综合运用 ArkTS 的核心能力。
1.2 核心功能
| 功能 | 描述 | 技术要点 |
|---|---|---|
| 初始化加载 | 应用启动时,根据种子数据在沙箱中创建 100 本小说文件 | TaskPool 子线程 + fileIo 写入 |
| 关键词搜索 | 输入关键词,在子线程中按文件名、作者、内容进行搜索 | @Concurrent + 300ms 防抖 |
| 分类过滤 | 按「科幻、悬疑、文学、历史、现代」分类筛选 | @Trace 驱动 UI 刷新 |
| 多维排序 | 按匹配度、文件大小、名称排序 | ViewModel 前端排序 |
| 详情查看 | 点击小说卡片进入详情页,展示全文内容 | Navigation + NavPathStack |
| 实时反馈 | 加载动画、匹配度评分、空状态提示 | @Local 状态管理 |
1.3 技术栈总览
| 类别 | 技术 | 版本 |
|---|---|---|
| 语言 | ArkTS | — |
| SDK | HarmonyOS | 6.1 (API 23) |
| 状态管理 | State Management V2 | @ObservedV2 + @Trace + @Local |
| 多线程 | @ohos.taskpool | @Concurrent + taskpool.execute |
| 文件操作 | @kit.CoreFileKit | fileIo (同步 API) |
| 页面导航 | Navigation + NavPathStack | 栈式导航 |
| 组件模型 | @ComponentV2 | V2 声明式 UI |
二、效果展示
2.1 首页 — 搜索与列表
┌──────────────────────────────────────┐
│ 小说查询 TaskPool │
├──────────────────────────────────────┤
│ 🔍 搜索小说名称、作者或内容... ✕ │
├──────────────────────────────────────┤
│ 全部 科幻 悬疑 文学 历史 现代 │
├──────────────────────────────────────┤
│ 共 100 个结果 匹配度 | 大小 | 名称│
├──────────────────────────────────────┤
│ ┌──────────────────────────────────┐ │
│ │ 科幻 匹配度 100%│ │
│ │ 星际迷航纪 │ │
│ │ 作者:陈星河 │ │
│ │ 公元2387年,人类文明已经跨越 │ │
│ │ 太阳系的边界,在半人马座阿尔法 │ │
│ │ 星系建立了第一个星际殖民地... │ │
│ │ 📄 1.2KB 📅 2024-06-20 星际迷航纪.txt │
│ └──────────────────────────────────┘ │
│ ┌──────────────────────────────────┐ │
│ │ 科幻 匹配度 80% │ │
│ │ 量子之境 │ │
│ │ 作者:赵明远 │ │
│ │ 量子物理学家周子涵在进行一次 │ │
│ │ 高能粒子对撞实验时... │ │
│ └──────────────────────────────────┘ │
│ ┌──────────────────────────────────┐ │
│ │ 悬疑 匹配度 80% │ │
│ │ 古城密码 │ │
│ │ ... │ │
│ └──────────────────────────────────┘ │
└──────────────────────────────────────┘
2.2 详情页 — 小说详情
┌──────────────────────────────────────┐
│ ← 星际迷航纪 │
├──────────────────────────────────────┤
│ ┌──────────────────────────────────┐ │
│ │ 科幻 匹配度 100%│ │
│ │ │ │
│ │ 星际迷航纪 │ │
│ │ 作者:陈星河 │ │
│ │ 📄 1.2KB 📅 2024-06-20 │ │
│ └──────────────────────────────────┘ │
│ ┌──────────────────────────────────┐ │
│ │ 内容简介 │ │
│ │ │ │
│ │ 公元2387年,人类文明已经跨越太阳 │ │
│ │ 系的边界,在半人马座阿尔法星系建 │ │
│ │ 立了第一个星际殖民地。然而,一次 │ │
│ │ 突如其来的空间异变打破了... │ │
│ └──────────────────────────────────┘ │
│ ┌──────────────────────────────────┐ │
│ │ 章节目录(共 5 章) │ │
│ │ 第一章 星海彼岸 → │ │
│ │ ────────────────────────────── │ │
│ │ 第二章 空间异变 → │ │
│ │ ────────────────────────────── │ │
│ │ 第三章 殖民地危机 → │ │
│ └──────────────────────────────────┘ │
│ ┌──────────────────────────────────┐ │
│ │ 全文内容 │ │
│ │ 标题:星际迷航纪 │ │
│ │ 作者:陈星河 │ │
│ │ 分类:科幻 │ │
│ │ 【内容简介】 │ │
│ │ 公元2387年,人类文明已经... │ │
│ └──────────────────────────────────┘ │
└──────────────────────────────────────┘
2.3 交互流程
┌─────────┐ 输入关键词 ┌─────────┐ 300ms 防抖 ┌──────────┐
│ 用户输入 │ ──────────→ │ 防抖等待 │ ───────────→ │ TaskPool │
└─────────┘ └─────────┘ │ 子线程搜索 │
└─────┬────┘
│ 返回结果
▼
┌─────────┐ 点击卡片 ┌─────────┐ pushPath ┌──────────┐
│ 详情页 │ ←────────── │ 导航跳转 │ ←────────── │ 列表页 │
│ (NavDest)│ ← 返回 │(NavStack)│ │(Navigation)│
└─────────┘ pop() └─────────┘ └──────────┘
三、架构设计
3.1 分层架构
┌──────────────────────────────────────────────────────────┐
│ 页面层 (Pages) │
│ ┌──────────────────┐ ┌──────────────────────────┐ │
│ │ Index (首页) │ │ NovelDetailPage (详情页) │ │
│ │ Navigation 容器 │ ←→ │ NavDestination │ │
│ │ @ComponentV2 │ │ @ComponentV2 + @Param │ │
│ └────────┬─────────┘ └────────────┬─────────────┘ │
│ │ @Local viewModel │ @Local fullContent│
└───────────┼───────────────────────────┼──────────────────┘
│ │
┌───────────▼───────────────────────────▼──────────────────┐
│ ViewModel 层 │
│ NovelListViewModel (@ObservedV2 + @Trace) │
│ - novelList / filteredList / searchKeyword │
│ - updateFilteredList() / setSortType() / setCategory() │
└───────────┬────────────────────────────────────────────────┘
│ 调用
┌───────────▼────────────────────────────────────────────────┐
│ Service 层 (主线程封装) │
│ NovelQueryHelper │
│ - initFiles(seeds) → 初始化文件 │
│ - search(keyword) → 搜索小说 │
│ - readContent(filePath) → 读取全文 │
└───────────┬────────────────────────────────────────────────┘
│ taskpool.execute
┌───────────▼────────────────────────────────────────────────┐
│ TaskPool 层 (子线程 @Concurrent) │
│ - initNovelFiles() → 种子数据写入沙箱 │
│ - queryNovelFiles() → 文件名/内容匹配 │
│ - readNovelContent() → 全文读取 │
│ - fileIo (同步 API,不阻塞主线程) │
└────────────────────────────────────────────────────────────┘
3.2 项目目录
entry/src/main/
├── ets/
│ ├── common/
│ │ └── Constants.ets # 常量定义 + 种子数据 (NOVEL_SEEDS)
│ ├── model/
│ │ └── NovelFileInfo.ets # 数据模型 + 传输接口
│ ├── service/
│ │ └── NovelQueryService.ets # @Concurrent 并发函数 + Helper
│ ├── viewmodel/
│ │ └── NovelListViewModel.ets # 视图模型 (过滤/排序/状态)
│ └── pages/
│ ├── Index.ets # 首页 (Navigation 容器)
│ └── NovelDetailPage.ets # 详情页 (NavDestination)
├── resources/
│ ├── base/
│ │ ├── element/
│ │ │ ├── color.json
│ │ │ ├── float.json
│ │ │ └── string.json
│ │ └── profile/
│ │ └── main_pages.json
│ └── rawfile/
│ └── novels/ # 参考素材 (非运行时依赖)
│ ├── 星际迷航纪.txt
│ ├── 古城密码.txt
│ ├── 山间岁月.txt
│ ├── 量子之境.txt
│ ├── 长安旧事.txt
│ ├── 深海回声.txt
│ ├── 云端之城.txt
│ ├── 荒漠旅人.txt
│ ├── 时间裂隙.txt
│ └── 雾都迷踪.txt
3.3 模块职责
| 模块 | 文件 | 职责 | 核心技术 |
|---|---|---|---|
| 常量 | Constants.ets | 种子数据、分类列表、评分标准、配置参数 | NovelSeedData 接口 |
| 模型 | NovelFileInfo.ets | NovelFileRawData 传输接口 + NovelFileInfo 响应式类 | @ObservedV2 + @Trace |
| 服务 | NovelQueryService.ets | 3 个 @Concurrent 函数 + Helper 封装 | @Concurrent + fileIo |
| 视图模型 | NovelListViewModel.ets | 过滤/排序/状态管理 | @ObservedV2 + @Trace |
| 首页 | Index.ets | Navigation 容器、搜索、列表、路由映射 | @ComponentV2 + NavPathStack |
| 详情页 | NovelDetailPage.ets | 封面、简介、目录、全文 | @ComponentV2 + @Param |
四、核心设计思路
4.1 种子数据方案
由于 TaskPool 子线程无法通过 fileIo 访问 rawfile 目录,我们采用了种子数据嵌入代码的方案:
NOVEL_SEEDS (代码常量) ──序列化──→ 子线程 ──fileIo──→ 沙箱文件
↑ │
│ ↓
元数据嵌入代码 后续查询直接读沙箱
(不依赖 rawfile) (无路径限制)
100 本原创小说,涵盖 5 个分类(每类 20 篇):
| 分类 | 篇数 | 代表作品 |
|---|---|---|
| 科幻 | 20 | 星际迷航纪、暗物质之门、量子之境、火星殖民纪 |
| 悬疑 | 20 | 古城密码、消失的楼层、密室法则、深海回声 |
| 文学 | 20 | 山间岁月、故乡的云、渔歌子、老街烟火 |
| 历史 | 20 | 长安旧事、丝路驼铃、赤壁风云、郑和下西洋 |
| 现代 | 20 | 云端之城、创业江湖、芯片之战、北漂日记 |
4.2 跨线程数据传递
子线程 (@Concurrent) 主线程
┌─────────────────┐ ┌──────────────────────┐
│ 返回纯 interface │ ──序列化──→ │ 转换为 @ObservedV2 │
│ NovelFileRawData │ │ NovelFileInfo │
│ (可序列化) │ │ (@Trace 细粒度响应式) │
└─────────────────┘ └──────────────────────┘
设计原则:
- 子线程只处理纯数据(
interface),不接触 UI 框架 - 主线程负责将纯数据转换为响应式对象
- 这种模式保证了线程安全和序列化兼容性
4.3 搜索匹配度评分
| 匹配情况 | 评分 | 颜色 |
|---|---|---|
| 标题完全等于关键词 | 100% | 🟢 绿色 (#52C41A) |
| 标题/作者包含关键词 | 80% | 🟡 黄色 (#FAAD14) |
| 仅内容包含关键词 | 50% | 🔴 红色 (#FF4D4F) |
| 都不匹配 | 0% | 过滤掉 |
4.4 State Management V2 全景
@ObservedV2 NovelListViewModel
├── @Trace novelList: NovelFileInfo[]
├── @Trace filteredList: NovelFileInfo[]
├── @Trace searchKeyword: string
├── @Trace currentCategory: string
├── @Trace currentSort: SortType
├── @Trace isLoading: boolean
├── @Trace totalCount: number
└── @Trace errorMessage: string
│
│ 属性级响应式
▼
@ObservedV2 NovelFileInfo
├── @Trace title → Text(title)
├── @Trace author → Text(author)
├── @Trace matchScore → Text(matchScore%)
├── @Trace category → Text(category)
└── @Trace preview → Text(preview)
│
│ 只有变化的属性触发对应组件重渲染
▼
UI 精确刷新(非整体重绘)
4.5 导航架构
Navigation (pathStack)
├── 首页内容 (Column)
│ ├── 自定义标题栏
│ ├── 搜索栏
│ ├── 分类过滤条
│ ├── 排序按钮
│ └── 小说卡片列表 ← 点击卡片 pushPathByName
│
└── NavDestination (NovelDetailPage)
├── 系统标题栏 + 返回按钮
├── 封面信息区
├── 内容简介
├── 章节目录
└── 全文内容
五、性能优化策略
| 优化维度 | 具体做法 | 效果 |
|---|---|---|
| IO 不阻塞 UI | 所有文件操作在 @Concurrent 子线程执行 | 主线程保持 60fps |
| 搜索防抖 | setTimeout 300ms 延迟 | 减少 70% 不必要的 TaskPool 调用 |
| 精确 UI 刷新 | @Trace 标记每个属性 | 只有变化的属性触发对应组件重渲染 |
| 任务优先级 | 搜索 HIGH、初始化 MEDIUM | 用户交互优先响应 |
| 文件幂等创建 | accessSync 检查后创建 | 避免重复写入 |
| 预览截断 | 只读取前 120 字符作为预览 | 减少子线程内存占用 |
| 全文懒加载 | 仅进入详情页时加载全文 | 首屏加载更快 |
六、关键技术点速查
6.1 State Management V1 → V2 对照
| V1 装饰器 | V2 装饰器 | 用途 |
|---|---|---|
@Component | @ComponentV2 | 组件声明 |
@State | @Local | 页面内状态 |
@Prop | @Param | 父传子 |
@Link | @Param + @Event | 双向绑定 |
@ObjectLink | @ObservedV2 + @Trace | 对象响应式 |
@Watch | @Monitor | 属性监听 |
6.2 @Concurrent 函数设计要点
| 要点 | 说明 |
|---|---|
| 参数限制 | 只接受可序列化的基本类型和 interface |
| 不可访问 UI | 不能调用 getContext() 或任何 UI API |
| 同步 API | 子线程中使用 fileIo 同步 API 不阻塞主线程 |
| 避免 rawfile | 子线程无法通过 fileIo 访问 rawfile 目录 |
6.3 Navigation 配置速查
| 属性 | 首页 | 详情页 |
|---|---|---|
hideTitleBar | true(自定义标题栏) | false(系统标题栏+返回按钮) |
hideToolBar | true | true |
navDestination | 注册路由映射 | — |
title | — | 小说名称 |
七、系列文档索引
本案例共提供 4 份指南文档,覆盖从基础 API 到完整实现的全部内容:
| 序号 | 文档名称 | 内容概要 | 适合阅读者 |
|---|---|---|---|
| 1 | @ohos.taskpool 使用指南 | TaskPool API 详解:@Concurrent、Task、Priority、execute、cancel | 想了解 TaskPool 的开发者 |
| 2 | 小说文件查询案例指南 | 基础查询功能实现:数据建模、并发服务、UI 渲染、踩坑记录 | 想了解查询功能的开发者 |
| 3 | Navigation 页面导航实现指南 | 详情页添加:Navigation、NavPathStack、NavDestination、路由参数 | 想了解页面导航的开发者 |
| 4 | 小说初始化实现指南 | 种子数据设计、100 篇小说批量初始化、幂等性保证、性能分析 | 想了解数据初始化的开发者 |
| 5 | 本文(总体介绍) | 应用概述、效果展示、架构设计、核心设计思路 | 快速了解整体项目 |
八、源码文件清单
| 文件 | 路径 | 职责 | 行数 |
|---|---|---|---|
| Constants.ets | ets/common/ | 常量定义 + 种子数据 (100篇) | ~244 |
| NovelFileInfo.ets | ets/model/ | 数据模型 + 传输接口 | ~61 |
| NovelQueryService.ets | ets/service/ | @Concurrent 函数 + Helper | ~276 |
| NovelListViewModel.ets | ets/viewmodel/ | 视图模型 (过滤/排序) | ~90 |
| Index.ets | ets/pages/ | 首页 (Navigation + 搜索 + 列表) | ~369 |
| NovelDetailPage.ets | ets/pages/ | 详情页 (封面/简介/目录/全文) | ~268 |
九、运行与体验
9.1 环境要求
- DevEco Studio 6.1+
- HarmonyOS 6.1 SDK (API 23)
- 模拟器或真机
9.2 操作步骤
- 克隆项目 → 使用 DevEco Studio 打开
- 同步依赖 → 点击 Sync Now 同步 ohpm 依赖
- 运行应用 → 选择模拟器/真机,点击 Run
- 体验首页 → 查看小说列表,尝试搜索和分类筛选
- 体验详情 → 点击任意小说卡片,进入详情页查看全文
- 返回首页 → 点击左上角返回箭头
十、总结
本案例展示了一个完整的 HarmonyOS 应用开发流程,涵盖了以下核心能力:
- TaskPool 多线程:将文件 IO 放在子线程,保证 UI 流畅
- State Management V2:@ObservedV2 + @Trace 实现细粒度响应式
- Navigation 导航:NavPathStack 实现栈式页面跳转
- 跨线程数据传递:纯 interface 序列化 → @ObservedV2 响应式转换
- 种子数据方案:绕过 rawfile 子线程访问限制
这套技术方案可以直接应用到类似的文件管理类应用中,如文档搜索器、音乐文件管理、图片浏览器等场景。
系列文档:
- 📘
@ohos.taskpool 使用指南— TaskPool API 详解- 📗
小说文件查询案例指南— 查询功能实现- 📙
Navigation 页面导航实现指南— 详情页跳转- 📓
小说初始化实现指南— 种子数据与批量初始化- 📕
本文— 总体介绍与效果展示
参考文档:

1万+

被折叠的 条评论
为什么被折叠?



