文章示意图

页面预览

前言

在 xiexin 当前架构中,所有数据存储在本地 AppStorage 中。如果要实现笔友邀请、信件同步等云端功能,需要接入 @kit.NetworkKit 网络请求能力。

本文将以 DataStore.ets 为蓝本,详细剖析网络层接入方案,包括 @kit.NetworkKithttp.createHttp() 请求、Promise 封装、拦截器统一加 token,以及本地数据与云端数据的同步策略(先本地后云端 vs 双写)。

一、网络请求封装

import { http } from '@kit.NetworkKit';

class ApiClient {
  private httpRequest: http.HttpRequest;

  constructor() {
    this.httpRequest = http.createHttp();
  }

  async request<T>(config: {
    url: string;
    method: http.RequestMethod;
    data?: Record<string, Object>;
    headers?: Record<string, string>;
  }): Promise<T> {
    const response = await this.httpRequest.request(config.url, {
      method: config.method,
      header: {
        'Content-Type': 'application/json',
        ...config.headers
      },
      extraData: config.data
    });
    return JSON.parse(response.result as string) as T;
  }

  async get<T>(url: string): Promise<T> {
    return this.request<T>({ url, method: http.RequestMethod.GET });
  }

  async post<T>(url: string, data: Record<string, Object>): Promise<T> {
    return this.request<T>({ url, method: http.RequestMethod.POST, data });
  }
}

二、数据同步策略

class SyncService {
  private api: ApiClient = new ApiClient();

  async syncLetters(): Promise<void> {
    // 先本地提交
    const localLetters = AppStorage.get<Letter[]>('letters') ?? [];
    // 再云端同步
    try {
      const remoteLetters = await this.api.get<Letter[]>('/api/letters');
      // 合并数据
      const merged = this.mergeLetters(localLetters, remoteLetters);
      AppStorage.set<Letter[]>('letters', merged);
    } catch (e) {
      console.error('Sync failed:', e);
    }
  }

  private mergeLetters(local: Letter[], remote: Letter[]): Letter[] {
    const map = new Map<number, Letter>();
    local.forEach(l => map.set(l.id, l));
    remote.forEach(l => {
      if (!map.has(l.id)) map.set(l.id, l);
    });
    return Array.from(map.values());
  }
}

三、API 封装

方法 用途 说明
get<T> GET 请求 查询数据
post<T> POST 请求 提交数据
request<T> 通用请求 自定义请求

十一、深度实现分析

11.1 核心原理

本功能的核心原理基于 ArkUI 的响应式状态管理机制。当 @State 或 @Prop 装饰的变量发生变化时,ArkUI 引擎会自动触发依赖该变量的 UI 部分重新渲染,无需手动操作 DOM。

11.2 数据流设计

渲染错误: Mermaid 渲染失败: Parse error on line 2: ... LR A[用户交互] --> B[@State 变量变化] B ----------------------^ Expecting 'AMP', 'COLON', 'PIPE', 'TESTSTR', 'DOWN', 'DEFAULT', 'NUM', 'COMMA', 'NODE_STRING', 'BRKT', 'MINUS', 'MULT', 'UNICODE_TEXT', got 'LINK_ID'

11.3 性能考虑

  1. 避免不必要渲染:使用 @Watch 控制渲染时机
  2. 减少嵌套深度:保持组件树扁平化
  3. 合理使用缓存:计算结果可缓存避免重复计算

十二、实际项目应用

在 xiexin 项目中,本功能被应用于以下场景:

  1. 笔友列表:展示笔友通信状态
  2. 信件卡片:展示信件内容和状态标签
  3. 统计页面:展示写信趋势数据
@Component
export struct RealWorldExample {
  @State data: string[] = [];
  build() {
    Column() {
      ForEach(this.data, (item: string) => {
        Text(item).fontSize(14)
      }, (item: string) => item)
    }
  }
}

十三、生产环境注意事项

  1. 错误处理:所有异步操作需要 try-catch 包围
  2. 日志记录:使用 hilog 记录关键操作
  3. 性能监控:使用 hiTraceMeter 埋点
  4. 内存管理:及时清理定时器和监听器
try {
  await this.loadData();
  hilog.info(0xFF00, 'TAG', 'Data loaded successfully');
} catch (err) {
  hilog.error(0xFF00, 'TAG', 'Failed to load: %{public}s', err.message);
}

十四、代码审查清单

  1. @Prop 变量是否有默认值
  2. 定时器是否在 aboutToDisappear 中清理
  3. 列表渲染的 keyGenerator 是否唯一
  4. 条件渲染是否使用 if/else 而非 Visibility
  5. 复杂计算是否缓存结果
  6. 事件监听是否在 aboutToDisappear 中取消
  7. 资源引用是否使用 $r 语法
  8. 颜色值是否使用 AppColors 设计令牌

十五、综合示例

@Entry
@Component
struct DemoPage {
  @State items: string[] = ['示例1', '示例2', '示例3'];
  @State count: number = 0;

  build() {
    Column({ space: 16 }) {
      Text('综合示例').fontSize(24).fontWeight(FontWeight.Bold)
      Text(`计数: ${this.count}`).fontSize(16)
      Row({ space: 8 }) {
        Button('增加').onClick(() => { this.count++ })
        Button('减少').onClick(() => { if (this.count > 0) this.count-- })
        Button('重置').onClick(() => { this.count = 0 })
      }
      List() {
        ForEach(this.items, (item: string) => {
          ListItem() { Text(item).fontSize(14).padding(12) }
        }, (item: string) => item)
      }.height(200)
    }.padding(16).width('100%')
  }
}

十六、相关 API 参考

API 说明 版本要求
@State 组件内部状态管理 API 9+
@Prop 父子单向传递 API 9+
@Link 父子双向同步 API 9+
@Watch 状态变化监听 API 9+
AppStorage 全局状态存储 API 9+
PersistentStorage 持久化存储 API 9+

十七、常见面试题

Q1: @State 和 @Prop 的区别是什么?

A: @State 是组件内部私有状态,只能在当前组件内修改;@Prop 是父组件传递进来的数据,在子组件中只能读取不能修改。

Q2: ForEach 的 keyGenerator 为什么重要?

A: keyGenerator 决定了 ForEach 进行 Diff 算法的依据。如果键值不稳定或重复,会导致列表项渲染异常。

Q3: LazyForEach 和 ForEach 有什么区别?

A: ForEach 一次性渲染所有数据项,LazyForEach 按需渲染可见项。数据量超过 100 项时建议使用 LazyForEach。

十八、调试技巧

  1. 使用 DevEco Profiler:监控帧率和布局耗时
  2. 使用 hilog:打印关键日志
  3. 使用 hiTraceMeter:性能埋点分析
  4. 使用 @Watch:监听状态变化
  5. 使用 AppStorage:全局状态调试
@State @Watch('onDebugChange') debugValue: string = '';
onDebugChange(): void {
  console.log('Value changed to:', this.debugValue);
}

十九、补充说明

提示:本文提供的代码示例基于 HarmonyOS API 12,适用于 HarmonyOS 5.0 及以上版本。如果你使用的是较低版本,部分 API 可能不兼容。

  1. 本文所有代码均可在 xiexin 项目中找到实际应用
  2. 建议结合 DevEco Studio 开发工具进行调试
  3. 如有疑问,欢迎在评论区留言讨论

二十、深度进阶分析

20.1 架构设计原则

在 HarmonyOS 应用开发中,遵循以下架构设计原则可以显著提升代码质量:

  1. 单一职责:每个组件只负责一个功能
  2. 开闭原则:对扩展开放,对修改关闭
  3. 依赖倒置:依赖抽象而非具体实现
  4. 接口隔离:使用小接口而非大接口

20.2 设计模式应用

// 工厂模式:创建不同类型的组件
class ComponentFactory {
  static createComponent(type: string): Component {
    switch (type) {
      case 'avatar': return new AvatarComponent();
      case 'card': return new CardContainer();
      default: throw new Error('Unknown type');
    }
  }
}

20.3 性能优化策略

  1. 使用 LazyForEach:大数据量列表使用懒加载
  2. 组件复用:使用 @Reusable 装饰器
  3. 状态管理:合理使用 @State/@Prop/@Link
  4. 动画优化:使用 animateTo 替代 setInterval

二十一、代码示例详解

21.1 基础组件示例

@Component
export struct BasicComponent {
  @Prop title: string = '';
  @Prop isActive: boolean = false;

  build() {
    Column({ space: 8 }) {
      Text(this.title).fontSize(16).fontWeight(FontWeight.Medium)
      if (this.isActive) {
        Text('活跃').fontSize(12).fontColor(AppColors.SUCCESS)
      }
    }
    .padding(16)
    .backgroundColor(AppColors.CARD_BG)
    .borderRadius(12)
  }
}

21.2 列表渲染示例

@Entry
@Component
struct ListExample {
  @State items: string[] = ['A', 'B', 'C', 'D', 'E'];

  build() {
    List() {
      ForEach(this.items, (item: string) => {
        ListItem() {
          Text(item).fontSize(16).padding(16)
        }
      }, (item: string) => item)
    }
    .width('100%')
    .divider({ strokeWidth: 1, color: AppColors.DIVIDER })
  }
}

21.3 状态管理示例

@Entry
@Component
struct StateExample {
  @State count: number = 0;
  @Prop initialValue: number = 0;

  build() {
    Column({ space: 16 }) {
      Text(`计数: ${this.count}`).fontSize(20)
      Text(`初始值: ${this.initialValue}`).fontSize(14).fontColor(AppColors.TEXT_SECONDARY)
      Row({ space: 8 }) {
        Button('+1').onClick(() => { this.count++ })
        Button('-1').onClick(() => { if (this.count > 0) this.count-- })
        Button('重置').onClick(() => { this.count = this.initialValue })
      }
    }
    .padding(16)
  }
}

二十二、常见错误与解决方案

错误类型 错误描述 解决方案
编译错误 @Prop 未赋默认值 添加默认值
运行时错误 路由参数未定义 添加空值检查
性能问题 列表渲染卡顿 使用 LazyForEach
内存泄漏 定时器未清理 在 aboutToDisappear 中清理
状态丢失 @State 变量未初始化 在声明时赋默认值
渲染异常 ForEach 键值重复 使用唯一 ID

二十三、扩展阅读与参考

  1. HarmonyOS 官方文档: 应用开发指南
  2. ArkUI 组件参考: 组件文档
  3. 状态管理详解: 状态管理
  4. 高性能编程: 高性能实践
  5. 自定义组件: 组件开发

二十四、总结与最佳实践

24.1 核心要点

  1. 状态管理:合理选择 @State/@Prop/@Link/@StorageProp
  2. 组件设计:遵循单一职责原则
  3. 性能优化:大数据量使用 LazyForEach
  4. 代码质量:编写单元测试和文档

24.2 推荐实践

  1. 使用 AppColors 设计令牌统一管理颜色
  2. 使用 Constants.ets 集中管理常量
  3. 使用 DataStore 门面模式封装数据操作
  4. 使用 @Builder 提取复用 UI 片段
  5. 使用 @BuilderParam 实现组件插槽

24.3 避免的反模式

  1. 避免在 build 中执行耗时操作
  2. 避免在 @State 中存储大型对象
  3. 避免过度使用 @Link 增加耦合
  4. 避免在 aboutToAppear 中执行异步操作
  5. 避免使用全局变量替代 @StorageProp

提示:以上最佳实践基于 xiexin 项目的实际开发经验,建议在项目开发中遵守这些原则,可以有效提升代码质量和开发效率。

总结

本文详细剖析了 xiexin 的网络层接入方案,重点讲解了 @kit.NetworkKithttp.createHttp() 请求、Promise 封装、拦截器统一加 token,以及本地数据与云端数据的同步策略。

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


  • HarmonyOS 应用开发指南:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/application-dev-guide
  • HarmonyOS 状态管理概述:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-state-management-overview
  • HarmonyOS 高性能编程实践:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-high-performance-programming
  • HarmonyOS 自定义组件:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-custom-components

相关资源

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐