3  第2章 应用架构设计

HarmonyOS应用开发者高级认证教程

Author

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和View

4.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应用架构设计的核心知识:

  1. Stage模型:掌握了UIAbility的完整生命周期(onCreate -> onWindowStageCreate -> onForeground -> onBackground -> onWindowStageDestroy -> onDestroy),理解了ExtensionAbility体系(FormExtension、WorkSchedulerExtension、ServiceExtension等),熟悉了Want机制的显式和隐式调用方式。

  2. 架构模式:学习了MVVM在HarmonyOS中的实践方式,理解了单向数据流架构和分层架构设计(数据层、领域层、表现层),掌握了依赖注入的实现方法。

  3. 组件间通信:掌握了EventHub事件通信、跨Ability数据传递、CommonEvent公共事件订阅发布、粘性事件和有序事件的使用场景。

  4. 应用包管理:理解了HAP/HSP/HAR三种模块类型的区别和应用场景,掌握了module.json5配置、动态特性模块和应用签名分发流程。

  5. 后台任务管理:学习了长时任务和延迟任务的申请与管理,掌握了后台继续运行的最佳实践。

  6. 进程线程模型:理解了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将耗时操作放到子线程执行。