渐进式编程课
鸿蒙 目录
第 18 课2026.07.28

适用场景:页面需要请求网络数据、读取数据库,且希望请求实现可以复用和独立测试

第 18 课:数据服务与页面职责分离

  • 日期:2026-07-28
  • 课程序号:第 18 课
  • 知识点:独立数据服务、页面与数据层的职责边界
  • 适用场景:页面需要请求网络数据、读取数据库,且希望请求实现可以复用和独立测试

承接上一课的异步数据加载:上一课由页面同时实现 queryMessages() 和渲染逻辑;本课把数据获取下沉到服务层,页面只负责触发加载、保存页面状态和渲染结果。

核心概念

把职责分成两层:

text
页面组件:生命周期触发 -> 调用服务 -> 更新页面状态 -> 渲染 UI
数据服务:执行数据请求 -> 返回 Promise 结果

服务层不操作 @State,页面也不关心数据来自网络还是数据库。这样多个页面可以复用同一个服务,替换真实数据源时也不需要改 UI 结构。

最小 ArkTS / ArkUI 示例

ts
class MessageService {
  static queryMessages(): Promise<string[]> {
    return Promise.resolve(['系统通知', '学习提醒']);
  }
}

@Entry
@Component
struct MessagePage {
  @State loading: boolean = false;
  @State items: string[] = [];
  @State errorMessage: string = '';

  aboutToAppear(): void {
    this.loadMessages();
  }

  async loadMessages(): Promise<void> {
    this.loading = true;
    this.errorMessage = '';

    try {
      this.items = await MessageService.queryMessages();
    } catch {
      this.errorMessage = '加载失败,请重试';
    } finally {
      this.loading = false;
    }
  }

  build() {
    Column({ space: 12 }) {
      if (this.loading) {
        Text('加载中...')
      } else if (this.errorMessage.length > 0) {
        Text(this.errorMessage)
          .fontColor(Color.Red)
      } else {
        ForEach(this.items, (item: string) => {
          Text(item)
        }, (item: string) => item)
      }
    }
    .width('100%')
    .padding(20)
  }
}

关键边界在 MessageService.queryMessages(): Promise<string[]>:方法签名承诺异步返回字符串数组;页面通过 await 接收结果,再写入自己的 @State。服务层不直接修改页面状态。

3~5 分钟练习

给 MessageService 增加 queryUnreadCount(): Promise<number>,返回未读数量 2;页面新增 @State unreadCount,加载消息成功后同时获取并显示未读数量。

参考答案

服务层增加:

ts
static queryUnreadCount(): Promise<number> {
  return Promise.resolve(2);
}

页面增加状态:

ts
@State unreadCount: number = 0;

在 try 中增加调用:

ts
this.items = await MessageService.queryMessages();
this.unreadCount = await MessageService.queryUnreadCount();

在 build() 的 Column 中显示:

ts
Text(`未读消息:${this.unreadCount}`)

与上一课的联系

上一课建立了加载、成功和失败三类页面状态;本课保留这套状态语义,只把数据获取实现移出组件。页面仍由真实请求结果驱动 UI,没有在展示层缓存、兜底或伪造状态。