前面四篇把工作台的框架、交互、性能、适配都搞定了,页面看着已经挺像那么回事。但离真正上线还有距离——用户打开应用不能白屏,断网不能直接崩,退出再进来状态不能丢。这篇讲工程收尾的事情,都是细节,但没做好就是没法上线。

很多人开发的时候只顾着功能实现,忽略了异常处理和数据持久化。Demo 阶段没问题,真给用户用,各种奇奇怪怪的问题都来了。这篇就把我们项目上线前做的那些收尾工作讲一讲。

数据持久化架构图

数据持久化:Preferences 存用户偏好

用户上次打开应用时选了哪个导航、滚动到了哪里,这些信息要存下来。下次打开应用直接恢复,不用用户重新操作一遍。

HarmonyOS 提供了 Preferences 轻量存储,适合存小的键值对。我们项目里存了用户的主题选择、默认导航项、上次阅读位置。

下面是封装的 Preferences 工具类,文件位置在 utils/PreferenceUtil.ets

import preferences from '@ohos.data.preferences';

export class PreferenceUtil {
  private static preferencesInstance: preferences.Preferences | null = null;
  private static readonly STORE_NAME = 'workbench_prefs';

  // 初始化 Preferences
  static async init(context: Context) {
    if (!this.preferencesInstance) {
      this.preferencesInstance = await preferences.getPreferences(
        context,
        this.STORE_NAME
      );
    }
  }

  // 保存选中的导航 ID
  static async saveSelectedNavId(navId: number) {
    await this.preferencesInstance?.put('selected_nav_id', navId);
    await this.preferencesInstance?.flush();
  }

  // 读取选中的导航 ID
  static async getSelectedNavId(): Promise {
    const value = await this.preferencesInstance?.get('selected_nav_id', 0);
    return value as number;
  }

  // 保存上次阅读位置
  static async saveLastReadPosition(itemId: string) {
    await this.preferencesInstance?.put('last_read_item', itemId);
    await this.preferencesInstance?.flush();
  }

  // 清除所有数据(退出登录时用)
  static async clear() {
    await this.preferencesInstance?.clear();
    await this.preferencesInstance?.flush();
  }
}

在 EntryAbility 的 onCreate 里初始化,页面 aboutToAppear 的时候读取。这样用户每次打开应用,都能回到上次离开的位置。

注意:Preferences 是异步的,不要在 build 方法里同步调用。读取数据放在 aboutToAppear 里,读到了再更新 @State,UI 自动刷新。

异常兜底:断网、空数据、加载失败

用户打开应用,网络慢怎么办?接口报错怎么办?列表是空的怎么办?这些情况都要有兜底 UI,不能直接白屏或者崩掉。

我们在 ContentList 组件里做了三态处理:加载中、空数据、错误。之前第二篇讲过思路,这里讲一下具体的异常处理逻辑:

@Component
export struct ContentList {
  @Prop items: ContentItem[] = [];
  @Prop isLoading: boolean = false;
  @Prop errorMsg: string = '';
  onRetry: () => void = () => {};

  build() {
    if (this.isLoading) {
      // 加载中:显示 loading
      this.LoadingView()
    } else if (this.errorMsg) {
      // 错误状态:显示错误信息和重试按钮
      this.ErrorView()
    } else if (this.items.length === 0) {
      // 空数据:显示空状态提示
      this.EmptyView()
    } else {
      // 正常列表
      this.NormalListView()
    }
  }

  @Builder
  LoadingView() {
    Column() {
      LoadingProgress()
        .width(40)
        .height(40)
      Text('加载中...')
        .fontSize(14)
        .fontColor('#999999')
        .margin({ top: 12 })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }

  @Builder
  ErrorView() {
    Column() {
      Text(this.errorMsg)
        .fontSize(14)
        .fontColor('#ff4444')
        .textAlign(TextAlign.Center)
      Button('重新加载')
        .margin({ top: 16 })
        .backgroundColor('#007aff')
        .onClick(() => {
          this.onRetry();
        })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }

  @Builder
  EmptyView() {
    Column() {
      Text('暂无内容')
        .fontSize(14)
        .fontColor('#999999')
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

这套三态处理看起来简单,但真到线上很重要。我们上线前测试了弱网、断网、接口超时等各种情况,确保每种状态都有友好提示,不会出现白屏或者崩溃。

页面三态处理流程图

全局错误处理

除了页面级的异常处理,还要有全局的错误兜底。应用启动的时候注册全局错误监听,未捕获的异常不会直接闪退,而是提示用户应用出错了,然后自动重启。

这个一般在 EntryAbility 里配置。我们项目里用了 try-catch 包裹关键流程,同时监听系统的 error 事件,把错误信息上报到日志系统,方便后续排查问题。

上线前的性能检查清单

功能写完了,上线前一定要做一轮性能检查。我们整理了一个清单:

1. 启动速度:冷启动时间要控制在 2 秒以内。用 DevEco Studio 的启动分析工具看,有没有耗时操作放在了主线程。

2. 内存占用:连续操作 10 分钟,看内存有没有持续上涨。如果有,大概率是内存泄漏。重点检查图片缓存、事件监听有没有及时释放。

3. 列表滑动流畅度:在低端机上滑动列表,FPS 能不能稳定在 50 以上。掉帧多的话回头看第三篇的优化方法。

4. 电量消耗:后台运行一段时间,看耗电量是否正常。定时器、网络请求不要太频繁。

5. 多机型适配:手机、折叠屏、平板都跑一遍,确认布局没有问题。横竖屏切换也测一下,状态有没有丢失。

工程收尾的其他细节

日志规范:开发的时候 console.log 到处都是,上线前要清理掉。封装一个 Logger 工具类,debug 模式打日志,release 模式自动关闭。

代码规范:统一命名规范,删掉注释掉的无用代码。TS 类型检查要严格,不要用 any。

版本号管理:app.json5 里的 versionCode 和 versionName 要更新。每次发版都要递增,不然应用市场检测不出来新版本。

这些都是小事,但上线前不做,后面改起来很麻烦。

写在最后

五篇连载到这里就结束了。从最开始搭工程框架,到状态管理、性能优化、多设备适配,最后到工程收尾上线。整个过程走下来,其实就是一个真实项目的开发流程。

HarmonyOS 7 的开发体验比之前好了很多,ArkUI 的声明式写法效率很高,响应式布局和状态管理的思路也和前端很像。但真要做出一个稳定流畅的应用,还是要在细节上下功夫——性能、适配、异常处理,哪一块没做到位,用户体验都会打折扣。

希望这个系列对大家做鸿蒙开发有帮助。有问题欢迎交流。

Logo

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

更多推荐