3 第2章 应用架构设计
HarmonyOS应用开发者高级认证教程
4 第2章 应用架构设计
4.1 学习目标
完成本章学习后,你将能够:
- 深入理解Stage模型下UIAbility的生命周期和ExtensionAbility体系
- 掌握Want机制的显式与隐式调用方式
- 设计MVVM和分层架构,实现依赖注入
- 熟练运用组件间通信机制(EventHub、CommonEvent等)
- 理解HAP/HSP/HAR模块结构和应用包管理
- 掌握后台任务管理和进程线程模型
4.2 2.1 Stage模型深入
4.2.1 2.1.1 UIAbility生命周期详解
UIAbility是HarmonyOS Stage模型中的核心组件,管理着用户界面的生命周期:
// EntryAbility.ets - UIAbility完整生命周期示例
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'
import { window } from '@kit.ArkUI'
import { hilog } from '@kit.PerformanceAnalysisKit'
export default class EntryAbility extends UIAbility {
private windowStageInstance: window.WindowStage | null = null
// 1. onCreate - Ability创建时调用,整个生命周期只执行一次
// 适合:初始化数据、注册监听器、申请权限
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(0x0000, 'LifeCycle', 'onCreate 开始')
// 判断启动原因
if (launchParam.launchReason ===
AbilityConstant.LaunchReason.NORMAL) {
hilog.info(0x0000, 'LifeCycle', '正常启动')
} else if (launchParam.launchReason ===
AbilityConstant.LaunchReason.START_REASON_SHARE) {
hilog.info(0x0000, 'LifeCycle', '分享启动')
}
// 获取Want中的启动参数
if (want.parameters) {
let action: string = want.parameters['action'] as string ?? ''
hilog.info(0x0000, 'LifeCycle', '启动参数: %{public}s', action)
}
// 初始化全局数据
this.initGlobalData()
}
// 2. onWindowStageCreate - 窗口创建时调用
// 适合:加载页面、设置窗口属性
onWindowStageCreate(windowStage: window.WindowStage): void {
hilog.info(0x0000, 'LifeCycle', 'onWindowStageCreate')
this.windowStageInstance = windowStage
// 设置窗口属性
windowStage.setWindowLayoutFullScreen(true)
// 监听窗口事件
windowStage.on('windowStageEvent', (event: number) => {
switch (event) {
case window.WindowStageEventType.SHOWN:
hilog.info(0x0000, 'LifeCycle', '窗口显示')
break
case window.WindowStageEventType.HIDDEN:
hilog.info(0x0000, 'LifeCycle', '窗口隐藏')
break
}
})
// 加载主页面
windowStage.loadContent('pages/Index', (err) => {
if (err.code) {
hilog.error(0x0000, 'LifeCycle',
'页面加载失败: %{public}s', JSON.stringify(err))
return
}
hilog.info(0x0000, 'LifeCycle', '页面加载成功')
})
}
// 3. onForeground - Ability切换到前台时调用
// 适合:恢复暂停的操作、刷新UI数据、重新开始动画
onForeground(): void {
hilog.info(0x0000, 'LifeCycle', 'onForeground - 进入前台')
// 刷新数据
this.refreshData()
// 恢复传感器监听等
this.resumeSensors()
}
// 4. onBackground - Ability切换到后台时调用
// 适合:释放资源、暂停动画、保存临时数据
onBackground(): void {
hilog.info(0x0000, 'LifeCycle', 'onBackground - 进入后台')
// 暂停传感器
this.pauseSensors()
// 保存临时数据
this.saveTemporaryData()
}
// 5. onWindowStageDestroy - 窗口销毁时调用
// 适合:释放窗口相关资源
onWindowStageDestroy(): void {
hilog.info(0x0000, 'LifeCycle', 'onWindowStageDestroy')
this.windowStageInstance = null
}
// 6. onDestroy - Ability销毁时调用
// 适合:释放所有资源、注销监听器
onDestroy(): void {
hilog.info(0x0000, 'LifeCycle', 'onDestroy - Ability销毁')
this.cleanupResources()
}
// 辅助方法
private initGlobalData(): void {
// 初始化全局数据
}
private refreshData(): void {
// 刷新数据
}
private resumeSensors(): void {
// 恢复传感器
}
private pauseSensors(): void {
// 暂停传感器
}
private saveTemporaryData(): void {
// 保存临时数据
}
private cleanupResources(): void {
// 清理资源
}
}UIAbility生命周期流程图说明:
应用启动
│
▼
onCreate() ──────── 初始化(仅一次)
│
▼
onWindowStageCreate() ─── 加载页面
│
▼
onForeground() ──────── 进入前台 ◄────────┐
│ │
▼ │
[用户可见/可交互] │
│ │
▼ │
onBackground() ─────── 进入后台 │
│ │
▼ │
[用户不可见] ──────────────────────────────┘
│
▼ (用户关闭应用/系统回收)
onWindowStageDestroy() ── 销毁窗口
│
▼
onDestroy() ─────────── 销毁Ability
4.2.2 2.1.2 ExtensionAbility体系
ExtensionAbility是HarmonyOS提供的扩展组件体系,用于实现特定场景的功能:
// 1. FormExtensionAbility - 桌面卡片
import { formBindingData, FormExtensionAbility } from '@kit.FormKit'
export default class CardExtension extends FormExtensionAbility {
// 卡片创建
onAddForm(want: Want): formBindingData.FormBindingData {
hilog.info(0x0000, 'CardExt', '卡片创建')
// 返回卡片初始数据
let formData: Record<string, Object> = {
title: "默认标题",
content: "默认内容",
updateTime: new Date().toLocaleString()
}
return formBindingData.createFormBindingData(formData)
}
// 卡片更新
onUpdateForm(formId: string): void {
hilog.info(0x0000, 'CardExt', `卡片更新: ${formId}`)
let formData: Record<string, Object> = {
title: "更新标题",
content: "更新内容",
updateTime: new Date().toLocaleString()
}
let data = formBindingData.createFormBindingData(formData)
this.context.updateForm(formId, data)
}
// 卡片销毁
onRemoveForm(formId: string): void {
hilog.info(0x0000, 'CardExt', `卡片销毁: ${formId}`)
}
// 定时更新
onCastEvent(event: formBindingData.FormEvents, formId: string): void {
if (event === formBindingData.FormEvents.UPDATE) {
this.onUpdateForm(formId)
}
}
}
// 2. WorkSchedulerExtensionAbility - 延迟任务
import { WorkSchedulerExtensionAbility, workScheduler } from
'@kit.WorkSchedulerKit'
export default class MyWorkScheduler extends WorkSchedulerExtensionAbility {
// 任务开始执行
onWorkStart(work: workScheduler.Work): void {
hilog.info(0x0000, 'WorkScheduler',
'任务开始执行: %{public}d', work.workId)
// 执行后台工作
this.doBackgroundWork(work)
}
// 任务停止
onWorkStop(work: workScheduler.Work): void {
hilog.info(0x0000, 'WorkScheduler',
'任务停止: %{public}d', work.workId)
// 清理工作
}
private doBackgroundWork(work: workScheduler.Work): void {
// 模拟后台工作
setTimeout(() => {
// 工作完成,设置任务成功状态
let completedWork: workScheduler.Work = work
completedWork.actualRepeatTimes = 0
this.context.setNextWorkTime(
work.workId, Date.now() + 3600000)
this.context.stopWork(work, true)
}, 5000)
}
}
// 3. ServiceExtensionAbility - 后台服务
import { ServiceExtensionAbility, Want } from '@kit.AbilityKit'
export default class MyService extends ServiceExtensionAbility {
onCreate(want: Want): void {
hilog.info(0x0000, 'Service', '服务创建')
}
onRequest(want: Want, startId: number): void {
hilog.info(0x0000, 'Service',
'服务请求, startId: %{public}d', startId)
// 处理服务请求
}
onDestroy(): void {
hilog.info(0x0000, 'Service', '服务销毁')
}
}4.2.3 2.1.3 Ability上下文与环境
// Ability上下文的使用
import { common } from '@kit.AbilityKit'
@Component
struct ContextExample {
// 通过@Entry装饰的组件可以获取UIAbilityContext
private context: common.UIAbilityContext =
getContext(this) as common.UIAbilityContext
aboutToAppear(): void {
// 1. 获取应用上下文
let appContext: common.ApplicationContext =
this.context.getApplicationContext()
// 2. 获取文件路径
let filesDir: string = this.context.filesDir
let cacheDir: string = this.context.cacheDir
let tempDir: string = this.context.tempDir
console.log(`文件目录: ${filesDir}`)
console.log(`缓存目录: ${cacheDir}`)
console.log(`临时目录: ${tempDir}`)
// 3. 获取应用信息
let bundleName: string = this.context.abilityInfo.bundleName
let abilityName: string = this.context.abilityInfo.name
console.log(`包名: ${bundleName}, Ability: ${abilityName}`)
// 4. 获取配置信息
let config: Configuration = this.context.config
console.log(`语言: ${config.language}`)
console.log(`国家: ${config.country}`)
}
// 5. 启动其他Ability
async startOtherAbility(): Promise<void> {
let want: Want = {
bundleName: "com.example.otherapp",
abilityName: "OtherAbility"
}
try {
await this.context.startAbility(want)
} catch (error) {
console.error(`启动失败: ${(error as Error).message}`)
}
}
build() {
Column() {
Text("上下文示例")
}
}
}4.2.4 2.1.4 Want机制详解
Want是HarmonyOS中组件间通信的载体,支持显式和隐式两种调用方式:
// 1. 显式Want - 明确指定目标组件
@Component
struct ExplicitWantExample {
private context: common.UIAbilityContext =
getContext(this) as common.UIAbilityContext
// 启动同一应用内的Ability
async startInnerAbility(): Promise<void> {
let want: Want = {
bundleName: "com.example.myapp",
abilityName: "DetailAbility",
// 传递参数
parameters: {
itemId: 1001,
itemName: "商品详情",
fromPage: "home"
}
}
try {
await this.context.startAbility(want)
} catch (error) {
console.error(`启动失败: ${(error as Error).message}`)
}
}
// 启动其他应用的Ability
async startExternalAbility(): Promise<void> {
let want: Want = {
bundleName: "com.example.mapapp",
abilityName: "MapAbility",
parameters: {
latitude: 39.9042,
longitude: 116.4074,
locationName: "北京"
}
}
await this.context.startAbility(want)
}
build() {
Column({ space: 16 }) {
Button("启动内部页面")
.onClick(() => { this.startInnerAbility() })
Button("启动外部应用")
.onClick(() => { this.startExternalAbility() })
}
}
}
// 2. 隐式Want - 通过Action/URI/Type匹配目标
@Component
struct ImplicitWantExample {
private context: common.UIAbilityContext =
getContext(this) as common.UIAbilityContext
// 打开网页
async openWebPage(): Promise<void> {
let want: Want = {
action: "ohos.want.action.viewData",
uri: "https://www.harmonyos.com"
}
await this.context.startAbility(want)
}
// 分享文本
async shareText(): Promise<void> {
let want: Want = {
action: "ohos.want.action.sendData",
parameters: {
"shareData": "这是一条分享消息"
}
}
// 使用startAbilityByImplicit会弹出选择器
let abilities =
await this.context.queryAbilityByWant(want)
if (abilities.length > 0) {
await this.context.startAbility(want)
}
}
// 选择图片
async pickImage(): Promise<void> {
let want: Want = {
action: "ohos.want.action.pickData",
type: "image/*"
}
await this.context.startAbility(want)
}
// 拨打电话
async makePhoneCall(): Promise<void> {
let want: Want = {
action: "ohos.want.action.dial",
uri: "tel:10086"
}
await this.context.startAbility(want)
}
// 发送邮件
async sendEmail(): Promise<void> {
let want: Want = {
action: "ohos.want.action.sendMail",
uri: "mailto:test@example.com",
parameters: {
"subject": "测试邮件",
"body": "这是一封测试邮件"
}
}
await this.context.startAbility(want)
}
build() {
Column({ space: 12 }) {
Button("打开网页").onClick(() => { this.openWebPage() })
Button("分享文本").onClick(() => { this.shareText() })
Button("选择图片").onClick(() => { this.pickImage() })
Button("拨打电话").onClick(() => { this.makePhoneCall() })
Button("发送邮件").onClick(() => { this.sendEmail() })
}
.width('100%')
.padding(16)
}
}
// 3. 接收Want参数
export default class DetailAbility extends UIAbility {
private receivedItemId: number = 0
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// 从Want中获取参数
if (want.parameters) {
this.receivedItemId = want.parameters['itemId'] as number ?? 0
let itemName: string =
want.parameters['itemName'] as string ?? ''
let fromPage: string =
want.parameters['fromPage'] as string ?? ''
hilog.info(0x0000, 'DetailAbility',
'收到参数 - ID: %{public}d, 名称: %{public}s, 来源: %{public}s',
this.receivedItemId, itemName, fromPage)
}
}
// 处理新Want(Ability已存在时再次被启动)
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
if (want.parameters) {
let newItemId: number =
want.parameters['itemId'] as number ?? 0
hilog.info(0x0000, 'DetailAbility',
'新的Want参数 - ID: %{public}d', newItemId)
// 更新UI数据
}
}
onWindowStageCreate(windowStage: window.WindowStage): void {
windowStage.loadContent('pages/Detail')
}
}4.3 2.2 应用架构模式
4.3.1 2.2.1 MVVM在HarmonyOS中的实践
MVVM(Model-View-ViewModel)是HarmonyOS推荐的应用架构模式:
// 1. Model层 - 数据模型定义
// models/ProductModel.ts
@Observed
export class ProductModel {
id: number
name: string
price: number
description: string
imageUrl: string
stock: number
constructor(
id: number,
name: string,
price: number,
description: string,
imageUrl: string,
stock: number
) {
this.id = id
this.name = name
this.price = price
this.description = description
this.imageUrl = imageUrl
this.stock = stock
}
get isAvailable(): boolean {
return this.stock > 0
}
get discountPrice(): number {
return this.price * 0.8 // 8折
}
}
// 2. ViewModel层 - 业务逻辑和状态管理
// viewmodels/ProductViewModel.ts
@Observed
export class ProductViewModel {
// UI状态
products: ProductModel[] = []
isLoading: boolean = false
errorMessage: string = ""
selectedCategory: string = "全部"
searchKeyword: string = ""
// 依赖注入 - 数据仓库
private repository: ProductRepository
constructor(repository: ProductRepository) {
this.repository = repository
}
// 加载商品列表
async loadProducts(): Promise<void> {
this.isLoading = true
this.errorMessage = ""
try {
this.products = await this.repository.fetchProducts(
this.selectedCategory,
this.searchKeyword
)
} catch (error) {
this.errorMessage = `加载失败: ${(error as Error).message}`
} finally {
this.isLoading = false
}
}
// 筛选商品
get filteredProducts(): ProductModel[] {
let result: ProductModel[] = this.products
// 按分类筛选
if (this.selectedCategory !== "全部") {
result = result.filter(
(p: ProductModel): boolean =>
p.description.includes(this.selectedCategory)
)
}
// 按关键词搜索
if (this.searchKeyword.length > 0) {
result = result.filter(
(p: ProductModel): boolean =>
p.name.includes(this.searchKeyword)
)
}
return result
}
// 添加商品到购物车
async addToCart(product: ProductModel): Promise<boolean> {
if (!product.isAvailable) {
this.errorMessage = "商品已售罄"
return false
}
try {
await this.repository.addToCart(product.id)
return true
} catch (error) {
this.errorMessage = `添加失败: ${(error as Error).message}`
return false
}
}
}
// 3. 数据仓库层
// repositories/ProductRepository.ts
export class ProductRepository {
private apiService: ApiService
private cache: Map<string, ProductModel[]> = new Map()
constructor(apiService: ApiService) {
this.apiService = apiService
}
async fetchProducts(
category: string,
keyword: string
): Promise<ProductModel[]> {
let cacheKey: string = `${category}_${keyword}`
// 检查缓存
if (this.cache.has(cacheKey)) {
return this.cache.get(cacheKey)!
}
// 从API获取
let data: Object[] = await this.apiService.get('/products', {
category: category,
keyword: keyword
})
let products: ProductModel[] = data.map(
(item: Object): ProductModel => {
let record = item as Record<string, Object>
return new ProductModel(
record['id'] as number,
record['name'] as string,
record['price'] as number,
record['description'] as string,
record['imageUrl'] as string,
record['stock'] as number
)
}
)
// 缓存结果
this.cache.set(cacheKey, products)
return products
}
async addToCart(productId: number): Promise<void> {
await this.apiService.post('/cart/add', { productId })
}
clearCache(): void {
this.cache.clear()
}
}
// 4. View层 - UI组件
// views/ProductListView.ets
@Component
struct ProductListView {
@ObjectLink viewModel: ProductViewModel
aboutToAppear(): void {
this.viewModel.loadProducts()
}
build() {
Column() {
// 搜索栏
Row() {
TextInput({ placeholder: "搜索商品..." })
.layoutWeight(1)
.onChange((value: string) => {
this.viewModel.searchKeyword = value
})
Button("搜索")
.onClick(() => {
this.viewModel.loadProducts()
})
}
.padding(16)
// 加载状态
if (this.viewModel.isLoading) {
LoadingProgress()
.width(50)
.height(50)
}
// 错误提示
if (this.viewModel.errorMessage.length > 0) {
Text(this.viewModel.errorMessage)
.fontColor('#FF0000')
.padding(16)
}
// 商品列表
List() {
ForEach(this.viewModel.filteredProducts,
(product: ProductModel) => {
ListItem() {
ProductCard({
product: product,
onAddToCart: () => {
this.viewModel.addToCart(product)
}
})
}
},
(product: ProductModel) => product.id.toString()
)
}
.width('100%')
.layoutWeight(1)
}
}
}
// 商品卡片组件
@Component
struct ProductCard {
product: ProductModel = new ProductModel(0, "", 0, "", "", 0)
onAddToCart: () => void = () => {}
build() {
Row() {
Image(this.product.imageUrl)
.width(80)
.height(80)
.borderRadius(8)
Column() {
Text(this.product.name)
.fontSize(16)
.fontWeight(FontWeight.Medium)
Text(`¥${this.product.price}`)
.fontSize(18)
.fontColor('#FF4444')
.fontWeight(FontWeight.Bold)
if (!this.product.isAvailable) {
Text("已售罄")
.fontSize(12)
.fontColor('#999999')
}
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Start)
.padding({ left: 12 })
Button("加入购物车")
.enabled(this.product.isAvailable)
.onClick(() => { this.onAddToCart() })
}
.padding(16)
.backgroundColor('#FFFFFF')
.borderRadius(12)
.margin({ bottom: 8 })
}
}4.3.2 2.2.2 单向数据流架构
// 单向数据流:Action -> Store -> State -> View -> Action
// 1. Action定义
interface Action {
type: string
payload?: Object
}
// 2. Store实现
class Store<S> {
private state: S
private listeners: Array<(state: S) => void> = []
private reducer: (state: S, action: Action) => S
constructor(initialState: S, reducer: (state: S, action: Action) => S) {
this.state = initialState
this.reducer = reducer
}
getState(): S {
return this.state
}
dispatch(action: Action): void {
// 通过reducer计算新状态
this.state = this.reducer(this.state, action)
// 通知所有监听器
this.notifyListeners()
}
subscribe(listener: (state: S) => void): () => void {
this.listeners.push(listener)
// 返回取消订阅函数
return (): void => {
let index: number = this.listeners.indexOf(listener)
if (index >= 0) {
this.listeners.splice(index, 1)
}
}
}
private notifyListeners(): void {
for (let listener of this.listeners) {
listener(this.state)
}
}
}
// 3. 使用示例
interface TodoState {
todos: string[]
filter: string
}
// Reducer
function todoReducer(state: TodoState, action: Action): TodoState {
switch (action.type) {
case 'ADD_TODO':
return {
...state,
todos: [...state.todos, action.payload as string]
}
case 'REMOVE_TODO':
let index: number = action.payload as number
return {
...state,
todos: state.todos.filter((_: string, i: number) => i !== index)
}
case 'SET_FILTER':
return {
...state,
filter: action.payload as string
}
default:
return state
}
}
// 创建Store
let todoStore = new Store<TodoState>(
{ todos: [], filter: 'all' },
todoReducer
)
// 在组件中使用
@Component
struct TodoView {
@State todos: string[] = []
@State newTodo: string = ""
aboutToAppear(): void {
// 订阅状态变化
todoStore.subscribe((state: TodoState) => {
this.todos = state.todos
})
// 初始化
this.todos = todoStore.getState().todos
}
build() {
Column() {
Row() {
TextInput({ placeholder: "添加待办..." })
.layoutWeight(1)
.onChange((value: string) => {
this.newTodo = value
})
Button("添加")
.onClick(() => {
if (this.newTodo.length > 0) {
todoStore.dispatch({
type: 'ADD_TODO',
payload: this.newTodo
})
this.newTodo = ""
}
})
}
.padding(16)
List() {
ForEach(this.todos, (todo: string, index: number) => {
ListItem() {
Row() {
Text(todo).layoutWeight(1)
Button("删除")
.onClick(() => {
todoStore.dispatch({
type: 'REMOVE_TODO',
payload: index
})
})
}
.padding(12)
}
}, (todo: string) => todo)
}
}
}
}4.3.3 2.2.3 分层架构设计
// 完整的分层架构实现
// ===== 数据层 (Data Layer) =====
// 数据源接口
interface DataSource<T> {
getAll(): Promise<T[]>
getById(id: number): Promise<T | null>
create(item: T): Promise<T>
update(item: T): Promise<T>
delete(id: number): Promise<void>
}
// 本地数据源实现
class LocalDataSource<T> implements DataSource<T> {
private tableName: string
private preferences: dataPreferences.Preferences | null = null
constructor(tableName: string) {
this.tableName = tableName
}
async init(context: common.Context): Promise<void> {
this.preferences = await dataPreferences.getPreferences(
context, this.tableName
)
}
async getAll(): Promise<T[]> {
if (!this.preferences) return []
let data: string = await this.preferences.get('data', '[]') as string
return JSON.parse(data) as T[]
}
async getById(id: number): Promise<T | null> {
let items: T[] = await this.getAll()
let found: T[] = items.filter(
(item: T): boolean =>
(item as Record<string, Object>)['id'] === id
)
return found.length > 0 ? found[0] : null
}
async create(item: T): Promise<T> {
let items: T[] = await this.getAll()
items.push(item)
await this.saveAll(items)
return item
}
async update(item: T): Promise<T> {
let items: T[] = await this.getAll()
let index: number = items.findIndex(
(i: T): boolean =>
(i as Record<string, Object>)['id'] ===
(item as Record<string, Object>)['id']
)
if (index >= 0) {
items[index] = item
await this.saveAll(items)
}
return item
}
async delete(id: number): Promise<void> {
let items: T[] = await this.getAll()
items = items.filter(
(item: T): boolean =>
(item as Record<string, Object>)['id'] !== id
)
await this.saveAll(items)
}
private async saveAll(items: T[]): Promise<void> {
if (this.preferences) {
await this.preferences.put('data', JSON.stringify(items))
await this.preferences.flush()
}
}
}
// 远程数据源实现
class RemoteDataSource<T> implements DataSource<T> {
private baseUrl: string
constructor(baseUrl: string) {
this.baseUrl = baseUrl
}
async getAll(): Promise<T[]> {
let response = await fetch(`${this.baseUrl}/items`)
return await response.json() as T[]
}
async getById(id: number): Promise<T | null> {
let response = await fetch(`${this.baseUrl}/items/${id}`)
return await response.json() as T
}
async create(item: T): Promise<T> {
let response = await fetch(`${this.baseUrl}/items`, {
method: 'POST',
body: JSON.stringify(item)
})
return await response.json() as T
}
async update(item: T): Promise<T> {
let id: number =
(item as Record<string, Object>)['id'] as number
let response = await fetch(`${this.baseUrl}/items/${id}`, {
method: 'PUT',
body: JSON.stringify(item)
})
return await response.json() as T
}
async delete(id: number): Promise<void> {
await fetch(`${this.baseUrl}/items/${id}`, {
method: 'DELETE'
})
}
}
// ===== 领域层 (Domain Layer) =====
// 仓库模式 - 统一数据访问接口
class UserRepository {
private localSource: LocalDataSource<User>
private remoteSource: RemoteDataSource<User>
constructor(
localSource: LocalDataSource<User>,
remoteSource: RemoteDataSource<User>
) {
this.localSource = localSource
this.remoteSource = remoteSource
}
// 优先从本地获取,再同步远程数据
async getUsers(): Promise<User[]> {
try {
// 先返回本地缓存数据
let localUsers: User[] = await this.localSource.getAll()
// 异步同步远程数据
this.syncRemoteData()
return localUsers
} catch (error) {
// 本地数据不可用,从远程获取
return await this.remoteSource.getAll()
}
}
private async syncRemoteData(): Promise<void> {
try {
let remoteUsers: User[] =
await this.remoteSource.getAll()
// 更新本地缓存
for (let user of remoteUsers) {
await this.localSource.update(user)
}
} catch (error) {
console.error("同步远程数据失败:", error)
}
}
}
// ===== 表现层 (Presentation Layer) =====
// 即上面MVVM中的ViewModel和View4.3.4 2.2.4 依赖注入与服务发现
// 1. 简单的依赖注入容器
class ServiceContainer {
private services: Map<string, Object> = new Map()
private factories: Map<string, () => Object> = new Map()
private singletons: Map<string, boolean> = new Map()
// 注册服务工厂
register<T>(name: string, factory: () => T, singleton: boolean = true): void {
this.factories.set(name, factory as () => Object)
this.singletons.set(name, singleton)
}
// 获取服务实例
resolve<T>(name: string): T {
// 如果是单例且已创建,直接返回
if (this.singletons.get(name) && this.services.has(name)) {
return this.services.get(name) as T
}
// 通过工厂创建实例
let factory = this.factories.get(name)
if (!factory) {
throw new Error(`服务未注册: ${name}`)
}
let instance: Object = factory()
// 如果是单例,缓存实例
if (this.singletons.get(name)) {
this.services.set(name, instance)
}
return instance as T
}
// 检查服务是否已注册
has(name: string): boolean {
return this.factories.has(name)
}
}
// 2. 使用依赖注入
// 创建全局容器
let container = new ServiceContainer()
// 注册服务
container.register<ApiService>('apiService', () => {
return new ApiService({
baseUrl: 'https://api.example.com',
timeout: 5000,
headers: new Map<string, string>()
})
})
container.register<UserRepository>('userRepository', () => {
let apiService = container.resolve<ApiService>('apiService')
let localSource = new LocalDataSource<User>('users')
let remoteSource = new RemoteDataSource<User>('https://api.example.com/users')
return new UserRepository(localSource, remoteSource)
})
container.register<ProductViewModel>('productViewModel', () => {
let repository = container.resolve<ProductRepository>('productRepository')
return new ProductViewModel(repository)
})
// 3. 在组件中使用
@Component
struct InjectedComponent {
private viewModel: ProductViewModel =
container.resolve<ProductViewModel>('productViewModel')
build() {
Column() {
Text("依赖注入示例")
}
}
}4.4 2.3 组件间通信
4.4.1 2.3.1 组件间事件通信(EventHub)
// 1. EventHub基本使用
import { common } from '@kit.AbilityKit'
// 在UIAbility中创建EventHub
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// EventHub通过context自动创建
let eventHub = this.context.eventHub
// 订阅事件
eventHub.on('userLogin', (data: Object) => {
let userData = data as Record<string, Object>
hilog.info(0x0000, 'EventHub',
'用户登录: %{public}s', userData['username'] as string)
})
eventHub.on('dataRefresh', (data: Object) => {
hilog.info(0x0000, 'EventHub', '数据需要刷新')
})
}
}
// 2. 在组件中使用EventHub
@Component
struct LoginPanel {
@State username: string = ""
@State password: string = ""
private context: common.UIAbilityContext =
getContext(this) as common.UIAbilityContext
build() {
Column({ space: 16 }) {
TextInput({ placeholder: "用户名" })
.onChange((value: string) => { this.username = value })
TextInput({ placeholder: "密码" })
.type(InputType.Password)
.onChange((value: string) => { this.password = value })
Button("登录")
.onClick(() => {
this.handleLogin()
})
}
.padding(24)
}
private async handleLogin(): Promise<void> {
try {
// 模拟登录
let result: boolean = await this.doLogin()
if (result) {
// 发布登录成功事件
this.context.eventHub.emit('userLogin', {
username: this.username,
loginTime: Date.now()
})
}
} catch (error) {
console.error("登录失败:", error)
}
}
private async doLogin(): Promise<boolean> {
// 模拟网络请求
return new Promise<boolean>((resolve) => {
setTimeout(() => resolve(true), 1000)
})
}
}
// 3. 监听事件的组件
@Component
struct UserProfile {
@State isLoggedIn: boolean = false
@State currentUser: string = ""
private context: common.UIAbilityContext =
getContext(this) as common.UIAbilityContext
aboutToAppear(): void {
// 订阅登录事件
this.context.eventHub.on('userLogin', (data: Object) => {
let userData = data as Record<string, Object>
this.isLoggedIn = true
this.currentUser = userData['username'] as string
})
// 订阅登出事件
this.context.eventHub.on('userLogout', () => {
this.isLoggedIn = false
this.currentUser = ""
})
}
aboutToDisappear(): void {
// 取消订阅
this.context.eventHub.off('userLogin')
this.context.eventHub.off('userLogout')
}
build() {
Column() {
if (this.isLoggedIn) {
Text(`欢迎, ${this.currentUser}`)
.fontSize(18)
Button("退出登录")
.onClick(() => {
this.context.eventHub.emit('userLogout', {})
})
} else {
Text("未登录")
.fontSize(18)
.fontColor('#999999')
}
}
}
}4.4.2 2.3.2 跨Ability数据传递
// 1. 通过Want传递数据
@Component
struct NavigationExample {
private context: common.UIAbilityContext =
getContext(this) as common.UIAbilityContext
// 传递简单数据
navigateToDetail(itemId: number, title: string): void {
let want: Want = {
bundleName: "com.example.myapp",
abilityName: "DetailAbility",
parameters: {
itemId: itemId,
title: title,
timestamp: Date.now()
}
}
this.context.startAbility(want)
}
// 传递复杂对象
navigateWithComplexData(user: User, settings: AppSettings): void {
let want: Want = {
bundleName: "com.example.myapp",
abilityName: "ProfileAbility",
parameters: {
userData: JSON.stringify(user),
settingsData: JSON.stringify(settings)
}
}
this.context.startAbility(want)
}
// 使用startAbilityForResult获取返回结果
async selectImage(): Promise<void> {
let want: Want = {
bundleName: "com.example.myapp",
abilityName: "ImagePickerAbility"
}
try {
let result: common.AbilityResult =
await this.context.startAbilityForResult(want)
if (result.resultCode === 0 && result.want?.parameters) {
let imagePath: string =
result.want.parameters['imagePath'] as string
console.log(`选择的图片: ${imagePath}`)
}
} catch (error) {
console.error("选择图片失败:", error)
}
}
build() {
Column({ space: 12 }) {
Button("查看详情")
.onClick(() => { this.navigateToDetail(1, "商品详情") })
Button("选择图片")
.onClick(() => { this.selectImage() })
}
}
}
// 2. 返回结果的Ability
export default class ImagePickerAbility extends UIAbility {
onWindowStageCreate(windowStage: window.WindowStage): void {
windowStage.loadContent('pages/ImagePicker')
}
// 返回结果给调用方
returnResult(imagePath: string): void {
let result: common.AbilityResult = {
resultCode: 0,
want: {
parameters: {
imagePath: imagePath
}
}
}
this.terminateSelfWithResult(result)
}
}4.4.3 2.3.3 公共事件订阅与发布(CommonEvent)
// 1. 发布公共事件
import { common } from '@kit.AbilityKit'
@Component
struct CommonEventPublisher {
private context: common.UIAbilityContext =
getContext(this) as common.UIAbilityContext
// 发布普通公共事件
publishEvent(): void {
let want: common.PublicWant = {
action: "com.example.MY_EVENT",
data: "事件数据",
parameters: {
key1: "value1",
key2: 42
}
}
this.context.publishEvent(want, (err: BusinessError) => {
if (err) {
console.error(`发布事件失败: ${err.message}`)
} else {
console.log("事件发布成功")
}
})
}
// 发布有序事件
publishOrderedEvent(): void {
let want: common.PublicWant = {
action: "com.example.ORDERED_EVENT",
parameters: {
priority_data: "重要数据"
}
}
this.context.publishEvent(want, {
isOrdered: true,
isSticky: false
})
}
// 发布粘性事件
publishStickyEvent(): void {
let want: common.PublicWant = {
action: "com.example.STICKY_EVENT",
parameters: {
config: JSON.stringify({ theme: "dark", fontSize: 16 })
}
}
this.context.publishEvent(want, {
isOrdered: false,
isSticky: true
})
}
build() {
Column({ space: 12 }) {
Button("发布普通事件").onClick(() => { this.publishEvent() })
Button("发布有序事件").onClick(() => { this.publishOrderedEvent() })
Button("发布粘性事件").onClick(() => { this.publishStickyEvent() })
}
}
}
// 2. 订阅公共事件
@Component
struct CommonEventSubscriber {
@State receivedData: string = "等待事件..."
private commonEventManager:
common.CommonEventManager | null = null
private subscriber:
common.CommonEventSubscriber | null = null
aboutToAppear(): void {
// 创建订阅者
let subscribeInfo: common.CommonEventSubscribeInfo = {
actions: [
"com.example.MY_EVENT",
"com.example.ORDERED_EVENT",
"com.example.STICKY_EVENT"
]
}
// 创建订阅管理器
commonEventManager = common.createCommonEventManager()
// 订阅事件
commonEventManager.createSubscriber(
subscribeInfo,
(err: BusinessError, subscriber: common.CommonEventSubscriber) => {
if (err) {
console.error(`创建订阅者失败: ${err.message}`)
return
}
this.subscriber = subscriber
// 注册事件回调
commonEventManager.subscribe(
subscriber,
(err: BusinessError, data: common.CommonEventData) => {
if (err) {
console.error(`订阅失败: ${err.message}`)
return
}
// 处理接收到的事件
this.handleEvent(data)
}
)
}
)
}
private handleEvent(data: common.CommonEventData): void {
let action: string = data.action ?? ""
console.log(`收到事件: ${action}`)
switch (action) {
case "com.example.MY_EVENT":
this.receivedData = `普通事件: ${data.data}`
break
case "com.example.ORDERED_EVENT":
this.receivedData = `有序事件: ${data.data}`
break
case "com.example.STICKY_EVENT":
this.receivedData = `粘性事件: ${data.data}`
break
}
}
aboutToDisappear(): void {
// 取消订阅
if (this.commonEventManager && this.subscriber) {
this.commonEventManager.unsubscribe(this.subscriber)
}
}
build() {
Column() {
Text(this.receivedData)
.fontSize(16)
.padding(16)
}
}
}
// 3. 订阅系统公共事件
@Component
struct SystemEventSubscriber {
@State networkStatus: string = "未知"
@State batteryLevel: number = 0
private subscriber: common.CommonEventSubscriber | null = null
aboutToAppear(): void {
let subscribeInfo: common.CommonEventSubscribeInfo = {
actions: [
"usual.event.NETWORK_STATE_CHANGED", // 网络状态变化
"usual.event.BATTERY_CHANGED", // 电池状态变化
"usual.event.SCREEN_ON", // 屏幕点亮
"usual.event.SCREEN_OFF" // 屏幕关闭
]
}
commonEventManager?.createSubscriber(
subscribeInfo,
(err: BusinessError, sub: common.CommonEventSubscriber) => {
if (err) return
this.subscriber = sub
commonEventManager?.subscribe(sub,
(err: BusinessError, data: common.CommonEventData) => {
if (err) return
this.handleSystemEvent(data)
}
)
}
)
}
private handleSystemEvent(data: common.CommonEventData): void {
switch (data.action) {
case "usual.event.NETWORK_STATE_CHANGED":
this.networkStatus = data.data ?? "未知"
break
case "usual.event.BATTERY_CHANGED":
if (data.parameters) {
this.batteryLevel =
data.parameters['batteryLevel'] as number ?? 0
}
break
}
}
aboutToDisappear(): void {
if (this.subscriber) {
commonEventManager?.unsubscribe(this.subscriber)
}
}
build() {
Column({ space: 12 }) {
Text(`网络状态: ${this.networkStatus}`)
Text(`电池电量: ${this.batteryLevel}%`)
}
}
}4.4.4 2.3.4 粘性事件与有序事件
// 粘性事件特点:
// 1. 事件发布后会一直保留在系统中
// 2. 新订阅者订阅时可以立即收到最近的粘性事件
// 3. 适合传递状态类信息(如配置变更)
// 有序事件特点:
// 1. 按照订阅者的优先级顺序传递
// 2. 高优先级订阅者可以截断事件,阻止传递给低优先级订阅者
// 3. 适合需要按优先级处理的场景
// 有序事件订阅 - 设置优先级
let orderedSubscribeInfo: common.CommonEventSubscribeInfo = {
actions: ["com.example.ORDERED_EVENT"],
// 优先级越高越先收到事件(-1000到1000)
priority: 100
}
// 在回调中截断事件
commonEventManager?.subscribe(subscriber,
(err: BusinessError, data: common.CommonEventData) => {
if (err) return
// 处理事件
let shouldStop: boolean = processData(data)
// 如果需要截断事件(不再传递给其他订阅者)
if (shouldStop) {
commonEventManager?.setStopOrder(subscriber, true)
}
// 修改事件数据传递给下一个订阅者
commonEventManager?.setCode(subscriber, 200)
commonEventManager?.setData(subscriber, "已处理的数据")
}
)4.5 2.4 应用包管理
4.5.1 2.4.1 HAP/HSP/HAR模块结构
// HarmonyOS应用包结构说明
/*
应用包结构:
├── entry/ # HAP模块 - 入口模块
│ ├── src/
│ │ ├── main/
│ │ │ ├── ets/
│ │ │ │ ├── entryability/
│ │ │ │ │ └── EntryAbility.ets
│ │ │ │ └── pages/
│ │ │ │ ├── Index.ets
│ │ │ │ └── Detail.ets
│ │ │ ├── resources/
│ │ │ └── module.json5
│ │ └── ohosTest/
│ ├── build-profile.json5
│ └── oh-package.json5
│
├── library/ # HAR模块 - 静态共享包
│ ├── src/
│ │ └── main/
│ │ ├── ets/
│ │ │ └── components/
│ │ │ ├── CommonButton.ets
│ │ │ └── CommonCard.ets
│ │ └── module.json5
│ └── oh-package.json5
│
├── feature/ # HSP模块 - 动态共享包
│ ├── src/
│ │ └── main/
│ │ ├── ets/
│ │ │ └── pages/
│ │ │ └── FeaturePage.ets
│ │ └── module.json5
│ └── oh-package.json5
│
├── build-profile.json5 # 项目级构建配置
└── oh-package.json5 # 项目级包配置
*/
// 模块类型对比:
// HAP (Harmony Ability Package):
// - 应用入口模块,可独立安装运行
// - 包含UIAbility和页面
// - 一个应用至少有一个HAP
// HAR (Harmony Archive):
// - 静态共享包,编译时打包进HAP
// - 共享代码和资源
// - 减少重复代码
// HSP (Harmony Shared Package):
// - 动态共享包,运行时按需加载
// - 适合大型应用的功能模块
// - 减小安装包体积4.5.2 2.4.2 module.json5配置详解
/*
// entry/src/main/module.json5
{
"module": {
// 模块名称
"name": "entry",
// 模块类型:entry(入口)、feature(特性)、shared(共享)
"type": "entry",
// 模块描述
"description": "$string:module_desc",
// 主元素
"mainElement": "EntryAbility",
// 设备类型
"deviceTypes": [
"phone",
"tablet"
],
// 投递方式
"deliveryWithInstall": true,
// 安装-free
"installationFree": false,
// 页面配置
"pages": "$profile:main_pages",
// Abilities配置
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"description": "$string:EntryAbility_desc",
"icon": "$media:icon",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:startIcon",
"startWindowBackground": "$color:start_window_background",
"exported": true,
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"action.system.home"
]
}
]
}
],
// 请求权限
"requestPermissions": [
{
"name": "ohos.permission.INTERNET",
"reason": "$string:network_permission_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
},
{
"name": "ohos.permission.GET_NETWORK_INFO",
"reason": "$string:network_info_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "always"
}
}
],
// 扩展能力配置
"extensionAbilities": [
{
"name": "CardExtension",
"srcEntry": "./ets/card/CardExtension.ets",
"type": "form",
"metadata": [
{
"name": "ohos.extension.form",
"resource": "$profile:form_config"
}
]
}
]
}
}
*/4.5.3 2.4.3 动态特性模块
// 动态特性模块(HSP)的使用
// 1. 在build-profile.json5中配置HSP模块
/*
{
"module": {
"name": "payment",
"srcPath": "./features/payment",
"targets": [
{
"name": "default",
"applyToProducts": ["default"]
}
]
}
}
*/
// 2. 在HAP中动态加载HSP
import { feature } from '@kit.CoreFileKit'
async function loadPaymentFeature(): Promise<void> {
try {
// 动态加载HSP模块
let paymentModule = await import('payment')
// 使用模块功能
paymentModule.initialize()
} catch (error) {
console.error(`加载支付模块失败: ${(error as Error).message}`)
}
}
// 3. 按需下载特性模块
async function installFeatureModule(moduleName: string): Promise<void> {
let bundleManager = await import('@ohos.bundle.bundleManager')
let context = getContext() as common.UIAbilityContext
try {
// 检查模块是否已安装
let bundleInfo = await bundleManager.getBundleInfoForSelf(
context.bundleName,
bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION
)
// 按需安装模块
await feature.installFeature(
moduleName,
context,
(err: BusinessError) => {
if (err) {
console.error(`安装失败: ${err.message}`)
} else {
console.log(`${moduleName} 安装成功`)
}
}
)
} catch (error) {
console.error("模块安装出错:", error)
}
}4.5.4 2.4.4 应用签名与分发
/*
应用签名流程:
1. 申请开发者证书
- 在AppGallery Connect注册开发者账号
- 生成密钥对(公私钥)
- 申请开发者证书(.cer文件)
2. 创建应用
- 在AppGallery Connect创建应用
- 获取Bundle Name
- 申请发布证书
3. 配置签名信息
- 在DevEco Studio中配置签名
- 生成.p7b签名文件
- 配置build-profile.json5
4. 构建签名包
- 构建HAP/HSP包
- 使用签名信息对包进行签名
- 生成.app文件
5. 提交分发
- 上传到AppGallery Connect
- 提交审核
- 发布到应用市场
// build-profile.json5签名配置
{
"app": {
"signingConfigs": [
{
"name": "default",
"type": "HarmonyOS",
"material": {
"certpath": "./signature/cert.cer",
"storePassword": "***",
"keyAlias": "mykey",
"keyPassword": "***",
"profile": "./signature/provision.p7b",
"signAlg": "SHA256withECDSA"
}
}
]
}
}
*/4.6 2.5 后台任务管理
4.6.1 2.5.1 长时任务(Long-time Task)
import { backgroundTaskManager } from '@kit.BackgroundTasksKit'
// 1. 申请长时任务
@Component
struct LongTimeTaskExample {
@State taskRunning: boolean = false
@State progress: number = 0
private longTimeId: number = -1
// 开始长时任务
async startLongTask(): Promise<void> {
try {
// 申请长时任务
let info: backgroundTaskManager.LongTimeTask = {
taskType: backgroundTaskManager.Type.DATA_TRANSFER
}
this.longTimeId = await backgroundTaskManager.startBackgroundRunning(
"audioPlaybackTask",
info,
() => {
console.log("长时任务申请成功")
}
)
this.taskRunning = true
// 执行后台任务
this.executeBackgroundWork()
} catch (error) {
console.error(`申请长时任务失败: ${(error as Error).message}`)
}
}
// 停止长时任务
async stopLongTask(): Promise<void> {
if (this.longTimeId !== -1) {
try {
await backgroundTaskManager.stopBackgroundRunning(
this.longTimeId
)
this.taskRunning = false
this.longTimeId = -1
console.log("长时任务已停止")
} catch (error) {
console.error(`停止长时任务失败: ${(error as Error).message}`)
}
}
}
private executeBackgroundWork(): void {
// 模拟后台数据传输
let intervalId: number = setInterval(() => {
this.progress += 5
if (this.progress >= 100) {
clearInterval(intervalId)
this.stopLongTask()
}
}, 1000)
}
aboutToDisappear(): void {
this.stopLongTask()
}
build() {
Column({ space: 20 }) {
Text(`任务状态: ${this.taskRunning ? "运行中" : "已停止"}`)
.fontSize(18)
Progress({ value: this.progress, total: 100 })
.width('80%')
Row({ space: 16 }) {
Button("开始任务")
.enabled(!this.taskRunning)
.onClick(() => { this.startLongTask() })
Button("停止任务")
.enabled(this.taskRunning)
.onClick(() => { this.stopLongTask() })
}
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}4.6.2 2.5.2 延迟任务(Delayed Task)
import { workScheduler } from '@kit.WorkSchedulerKit'
// 延迟任务适合不需要立即执行的工作
// 系统会在合适的时间(如充电、空闲时)执行
@Component
struct DelayedTaskExample {
@State taskStatus: string = "未注册"
// 注册延迟任务
registerDelayedTask(): void {
let work: workScheduler.Work = {
workId: 1001,
bundleName: "com.example.myapp",
abilityName: "MyWorkScheduler",
// 任务参数
parameters: {
"repeat": false,
"repeatCycleTime": 0,
"isCharging": false,
"isBatteryOk": true,
"networkType": workScheduler.NetworkType.ANY
}
}
try {
workScheduler.startWork(work)
this.taskStatus = "延迟任务已注册"
} catch (error) {
this.taskStatus = `注册失败: ${(error as Error).message}`
}
}
// 停止延迟任务
stopDelayedTask(): void {
let work: workScheduler.Work = {
workId: 1001,
bundleName: "com.example.myapp",
abilityName: "MyWorkScheduler"
}
try {
workScheduler.stopWork(work, false)
this.taskStatus = "延迟任务已停止"
} catch (error) {
this.taskStatus = `停止失败: ${(error as Error).message}`
}
}
build() {
Column({ space: 16 }) {
Text(`状态: ${this.taskStatus}`)
.fontSize(16)
Button("注册延迟任务")
.onClick(() => { this.registerDelayedTask() })
Button("停止延迟任务")
.onClick(() => { this.stopDelayedTask() })
}
.padding(24)
}
}4.6.3 2.5.3 后台继续运行管理
// 后台任务管理最佳实践
class BackgroundTaskManager {
private taskId: number = -1
private isRunning: boolean = false
// 根据任务类型选择合适的后台模式
async startTask(taskType: string): Promise<boolean> {
try {
let info: backgroundTaskManager.LongTimeTask
switch (taskType) {
case 'audio':
info = {
taskType: backgroundTaskManager.Type.AUDIO_PLAYBACK
}
break
case 'location':
info = {
taskType: backgroundTaskManager.Type.LOCATION
}
break
case 'dataTransfer':
info = {
taskType: backgroundTaskManager.Type.DATA_TRANSFER
}
break
default:
info = {
taskType: backgroundTaskManager.Type.DATA_TRANSFER
}
}
this.taskId = await backgroundTaskManager.startBackgroundRunning(
`task_${taskType}`,
info,
() => {
this.isRunning = true
console.log(`后台任务[${taskType}]启动成功`)
}
)
return true
} catch (error) {
console.error(`启动后台任务失败: ${(error as Error).message}`)
return false
}
}
async stopTask(): Promise<void> {
if (this.taskId !== -1 && this.isRunning) {
try {
await backgroundTaskManager.stopBackgroundRunning(this.taskId)
this.isRunning = false
this.taskId = -1
console.log("后台任务已停止")
} catch (error) {
console.error(`停止后台任务失败: ${(error as Error).message}`)
}
}
}
// 检查当前有效的后台任务
async getRunningTasks(): Promise<backgroundTaskManager.RunningTaskInfo[]> {
try {
return await backgroundTaskManager.getRunningTasks()
} catch (error) {
console.error("获取任务列表失败:", error)
return []
}
}
}4.7 2.6 应用进程与线程模型
4.7.1 2.6.1 进程架构
/*
HarmonyOS应用进程架构:
┌─────────────────────────────────────────────┐
│ 应用进程 │
│ ┌─────────────────────────────────────┐ │
│ │ 主线程 (UI Thread) │ │
│ │ ┌─────────┐ ┌─────────┐ │ │
│ │ │ UI渲染 │ │ 事件处理 │ │ │
│ │ └─────────┘ └─────────┘ │ │
│ └─────────────────────────────────────┘ │
│ ┌──────────┐ ┌──────────┐ │
│ │ Worker 1 │ │ Worker 2 │ (独立线程) │
│ └──────────┘ └──────────┘ │
│ ┌─────────────────────────────────────┐ │
│ │ TaskPool (线程池) │ │
│ │ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │ │
│ │ │ T1 │ │ T2 │ │ T3 │ │ T4 │ │ │
│ │ └────┘ └────┘ └────┘ └────┘ │ │
│ └─────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
关键原则:
1. 主线程负责UI渲染和事件处理,不能执行耗时操作
2. Worker拥有独立的V8引擎和内存空间
3. TaskPool由系统管理,自动分配和回收线程
4. 进程间通过IPC(进程间通信)机制交互
*/
// 进程信息获取
import { bundleManager } from '@kit.AbilityKit'
async function getProcessInfo(): Promise<void> {
let context = getContext() as common.UIAbilityContext
// 获取当前进程信息
let pid: number = process.pid
let ppid: number = process.ppid
console.log(`当前进程ID: ${pid}`)
console.log(`父进程ID: ${ppid}`)
// 获取应用信息
let bundleInfo: bundleManager.BundleInfo =
await bundleManager.getBundleInfoForSelf(
context.bundleName,
bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION
)
console.log(`应用名称: ${bundleInfo.label}`)
console.log(`版本号: ${bundleInfo.versionName}`)
}4.7.2 2.6.2 线程调度策略
// 1. TaskPool优先级设置
import taskpool from '@ohos.taskpool'
@Concurrent
function highPriorityTask(data: number[]): number {
// 优先级高的计算任务
return data.reduce((sum: number, val: number) => sum + val, 0)
}
@Concurrent
function lowPriorityTask(data: number[]): number {
// 优先级低的后台计算
let result: number = 0
for (let i: number = 0; i < data.length; i++) {
result += Math.sqrt(data[i])
}
return result
}
async function scheduleWithPriority(): Promise<void> {
// 高优先级任务 - 前台执行
let highTask = new taskpool.Task(highPriorityTask, [1, 2, 3, 4, 5])
await taskpool.execute(highTask, taskpool.Priority.HIGH)
// 中优先级任务 - 默认
let midTask = new taskpool.Task(highPriorityTask, [6, 7, 8])
await taskpool.execute(midTask, taskpool.Priority.MEDIUM)
// 低优先级任务 - 后台执行
let lowTask = new taskpool.Task(lowPriorityTask, [9, 10, 11])
await taskpool.execute(lowTask, taskpool.Priority.LOW)
}
// 2. Worker线程优先级
import worker from '@ohos.worker'
@Component
struct WorkerPriorityExample {
private highWorker: worker.ThreadWorker | null = null
private lowWorker: worker.ThreadWorker | null = null
aboutToAppear(): void {
// 创建高优先级Worker
this.highWorker = new worker.ThreadWorker(
'entry/ets/workers/HighPriorityWorker.ets',
{ name: "HighPriorityWorker" }
)
// 创建低优先级Worker
this.lowWorker = new worker.ThreadWorker(
'entry/ets/workers/LowPriorityWorker.ets',
{ name: "LowPriorityWorker" }
)
}
aboutToDisappear(): void {
this.highWorker?.terminate()
this.lowWorker?.terminate()
}
build() {
Column() {
Text("Worker优先级示例")
}
}
}4.7.3 2.6.3 进程间通信
// 1. 通过Want实现进程间数据传递(已在2.1.4详述)
// 2. 通过SharedArrayBuffer实现Worker与主线程共享内存
import worker from '@ohos.worker'
@Component
struct SharedMemoryExample {
@State result: string = ""
private myWorker: worker.ThreadWorker | null = null
aboutToAppear(): void {
// 创建共享内存
let sharedBuffer = new SharedArrayBuffer(1024)
let sharedView = new Int32Array(sharedBuffer)
// 初始化共享数据
sharedView[0] = 0 // 状态标志
sharedView[1] = 0 // 结果值
// 创建Worker并传递共享内存
this.myWorker = new worker.ThreadWorker(
'entry/ets/workers/SharedMemoryWorker.ets'
)
// 发送共享内存引用到Worker
this.myWorker.postMessage({
type: 'init',
buffer: sharedBuffer
}, [sharedBuffer])
// 监听Worker消息
this.myWorker.onmessage = (e: MessageEvents) => {
if (e.data.type === 'result') {
this.result = `计算结果: ${e.data.value}`
}
}
}
aboutToDisappear(): void {
this.myWorker?.terminate()
}
build() {
Column() {
Text(this.result).fontSize(18)
}
}
}
// Worker端 (SharedMemoryWorker.ets)
/*
import worker from '@ohos.worker'
const workerPort = worker.workerPort
let sharedView: Int32Array | null = null
workerPort.onmessage = (event: MessageEvents) => {
const data = event.data
if (data.type === 'init') {
// 接收共享内存
sharedView = new Int32Array(data.buffer)
startProcessing()
}
}
function startProcessing(): void {
// 使用共享内存进行计算
if (sharedView) {
sharedView[0] = 1 // 设置状态为"处理中"
let sum: number = 0
for (let i: number = 0; i < 1000; i++) {
sum += i
}
sharedView[1] = sum // 写入结果
sharedView[0] = 2 // 设置状态为"完成"
// 通知主线程
workerPort.postMessage({
type: 'result',
value: sum
})
}
}
*/4.7.4 2.6.4 资源管理与回收机制
// 1. 组件生命周期中的资源管理
@Component
struct ResourceManagementExample {
@State imageUri: string = ""
private timerIds: number[] = []
private listeners: Array<() => void> = []
aboutToAppear(): void {
// 注册资源
let timerId: number = setInterval(() => {
// 定时任务
}, 1000)
this.timerIds.push(timerId)
// 注册监听器
let listener = (): void => {
console.log("事件触发")
}
this.listeners.push(listener)
}
aboutToDisappear(): void {
// 释放所有定时器
for (let id of this.timerIds) {
clearInterval(id)
}
this.timerIds = []
// 清除监听器
this.listeners = []
// 释放图片资源
this.imageUri = ""
console.log("资源已全部释放")
}
build() {
Column() {
if (this.imageUri.length > 0) {
Image(this.imageUri)
.width(200)
.height(200)
}
}
}
}
// 2. 内存管理最佳实践
class MemoryManager {
private static instance: MemoryManager | null = null
private cache: Map<string, Object> = new Map()
private maxCacheSize: number = 50
static getInstance(): MemoryManager {
if (!MemoryManager.instance) {
MemoryManager.instance = new MemoryManager()
}
return MemoryManager.instance
}
// LRU缓存策略
set(key: string, value: Object): void {
// 如果缓存已满,删除最旧的条目
if (this.cache.size >= this.maxCacheSize) {
let firstKey: string = this.cache.keys().next().value
this.cache.delete(firstKey)
}
this.cache.set(key, value)
}
get(key: string): Object | undefined {
return this.cache.get(key)
}
// 清理缓存
clear(): void {
this.cache.clear()
}
// 获取缓存使用情况
getCacheInfo(): { size: number; maxSize: number } {
return {
size: this.cache.size,
maxSize: this.maxCacheSize
}
}
}
// 3. 图片资源优化
@Component
struct OptimizedImageList {
private imageCache: Map<string, PixelMap> = new Map()
aboutToDisappear(): void {
// 释放所有缓存的PixelMap
for (let pixelMap of this.imageCache.values()) {
pixelMap.release()
}
this.imageCache.clear()
}
build() {
List() {
ForEach(this.getImageUrls(), (url: string) => {
ListItem() {
Image(url)
.width('100%')
.height(200)
.objectFit(ImageFit.Cover)
.interpolation(ImageInterpolation.Medium)
}
}, (url: string) => url)
}
.cachedCount(5) // 预加载数量控制
}
private getImageUrls(): string[] {
return [
"https://example.com/image1.jpg",
"https://example.com/image2.jpg",
"https://example.com/image3.jpg"
]
}
}4.8 本章小结
本章深入讲解了HarmonyOS应用架构设计的核心知识:
Stage模型:掌握了UIAbility的完整生命周期(onCreate -> onWindowStageCreate -> onForeground -> onBackground -> onWindowStageDestroy -> onDestroy),理解了ExtensionAbility体系(FormExtension、WorkSchedulerExtension、ServiceExtension等),熟悉了Want机制的显式和隐式调用方式。
架构模式:学习了MVVM在HarmonyOS中的实践方式,理解了单向数据流架构和分层架构设计(数据层、领域层、表现层),掌握了依赖注入的实现方法。
组件间通信:掌握了EventHub事件通信、跨Ability数据传递、CommonEvent公共事件订阅发布、粘性事件和有序事件的使用场景。
应用包管理:理解了HAP/HSP/HAR三种模块类型的区别和应用场景,掌握了module.json5配置、动态特性模块和应用签名分发流程。
后台任务管理:学习了长时任务和延迟任务的申请与管理,掌握了后台继续运行的最佳实践。
进程线程模型:理解了HarmonyOS的进程架构、线程调度策略、进程间通信机制和资源管理方法。
4.9 练习题
4.9.1 一、单选题
1. UIAbility生命周期中,以下哪个方法在Ability从后台切换到前台时调用?
A. onCreate B. onWindowStageCreate C. onForeground D. onBackground
答案:C
解析: onForeground在UIAbility从后台切换到前台时调用,每次切换都会执行。onCreate只在首次创建时调用一次;onWindowStageCreate在窗口创建时调用;onBackground在进入后台时调用。
2. 以下关于HAP、HAR和HSP的描述,错误的是?
A. HAP是应用入口模块,可独立安装运行 B. HAR是静态共享包,编译时打包进HAP C. HSP是动态共享包,运行时按需加载 D. HAR可以包含UIAbility
答案:D
解析: HAR(Harmony Archive)是静态共享包,主要用于共享代码和资源,不能包含UIAbility。只有HAP(Harmony Ability Package)才能包含UIAbility。HSP是动态共享包,可以减小安装包体积。
3. Want机制中,隐式Want通过哪些属性匹配目标组件?
A. bundleName和abilityName B. action、uri和type C. parameters和data D. bundleName和action
答案:B
解析: 隐式Want通过action(动作)、uri(数据标识)和type(MIME类型)来匹配目标组件,系统会根据这些属性查找匹配的Ability。显式Want则直接指定bundleName和abilityName。
4.9.2 二、多选题
4. 以下哪些属于HarmonyOS的ExtensionAbility类型?
A. FormExtensionAbility B. WorkSchedulerExtensionAbility C. ServiceExtensionAbility D. UIExtensionAbility
答案:A、B、C、D
解析: HarmonyOS提供了多种ExtensionAbility类型,包括FormExtensionAbility(桌面卡片)、WorkSchedulerExtensionAbility(延迟任务)、ServiceExtensionAbility(后台服务)、UIExtensionAbility(UI扩展)等,用于实现不同场景的扩展功能。
5. 以下关于TaskPool和Worker的描述,正确的有哪些?
A. TaskPool由系统自动管理线程的创建和销毁 B. Worker拥有独立的V8引擎和内存空间 C. TaskPool适合长期运行的后台服务 D. Worker适合需要与主线程频繁通信的场景
答案:A、B、D
解析: TaskPool由系统管理线程池,自动创建和回收线程,适合短期计算任务;Worker拥有独立的V8引擎,适合长期运行和频繁通信的场景。TaskPool不适合长期运行的后台服务,那是Worker的适用场景。
4.9.3 三、判断题
6. EventHub只能在同一个UIAbility内的组件之间进行事件通信。
答案:正确
解析: EventHub是基于UIAbilityContext创建的事件总线,其作用域限定在同一个UIAbility内。如果需要跨Ability通信,应使用CommonEvent公共事件机制。
7. 粘性事件发布后,新订阅者订阅时可以立即收到最近一次发布的粘性事件。
答案:正确
解析: 粘性事件的特点是会在系统中保留,当新的订阅者订阅该事件时,即使没有新的事件发布,也能立即收到最近一次发布的粘性事件数据。这适合传递状态信息。
8. 在HarmonyOS中,主线程可以执行网络请求等耗时操作。
答案:错误
解析: 主线程(UI线程)负责界面渲染和用户交互事件处理,不应执行耗时操作(如网络请求、大量计算),否则会导致界面卡顿(掉帧)。应该使用TaskPool或Worker将耗时操作放到子线程执行。