HarmonyOS 教学实战(二):加入网络请求与缓存(让你的应用真正“像个正式 App”)

在上一篇文章中,我们已经完成了一个:

✔ 能运行

✔ 有完整页面

✔ 有组件拆分

✔ 有状态管理(V2)

✔ 有真实业务逻辑

任务清单 App

但说实话------

它还不像一个"真正的应用"。

因为它缺了两样东西:

网络请求 + 数据缓存

这一篇,我们就把应用往"真实产品"方向再推进一步。


一、这一篇我们要做什么?

继续在「任务清单 App」基础上,新增 4 个能力:

  1. 🔗 从服务器获取任务列表

  2. ⏳ 页面加载状态(Loading)

  3. 💾 本地缓存(Preferences)

  4. 🛜 网络失败自动兜底(缓存 + 提示)

完成后,你的应用将具备:

"有网用网,没网用缓存"的真实体验


二、整体设计思路(非常关键)

在写代码之前,先明确职责分工

层级 负责什么
UI 组件 展示数据、响应点击
Store(Model) 数据管理、业务逻辑
Network Service 网络请求
Cache Service 本地缓存
Page 组合 & 调度

📌 UI 永远不直接发请求

📌 UI 永远不直接操作缓存


三、准备一个"假的后端接口"

为了教学,我们假设服务端返回的数据格式如下:

复制代码
[
  { "id": 1, "title": "学习 HarmonyOS" },
  { "id": 2, "title": "写教学文章" }
]

接口地址(示例):

复制代码
https://example.com/api/tasks

四、第一步:封装网络请求层(推荐写法)

新增目录结构

复制代码
entry/
 └─ service/
     └─ TaskService.ets

service/TaskService.ets

复制代码
import http from '@ohos.net.http'
import { Task } from '../model/TaskModel'

export class TaskService {
  static async fetchTasks(): Promise<Task[]> {
    const httpRequest = http.createHttp()
    const response = await httpRequest.request(
      'https://example.com/api/tasks',
      {
        method: http.RequestMethod.GET,
        expectDataType: http.HttpDataType.STRING
      }
    )

    const data = JSON.parse(response.result as string)
    return data.map(item => new Task(item.id, item.title))
  }
}

教学重点

  • 网络请求单独封装

  • UI 完全不知道请求细节

  • 返回的是 业务对象 Task


五、第二步:加入本地缓存(Preferences)

新增缓存工具类

复制代码
entry/
 └─ service/
     └─ CacheService.ets

service/CacheService.ets

复制代码
import preferences from '@ohos.data.preferences'
import { Task } from '../model/TaskModel'

const CACHE_KEY = 'TASK_LIST'

export class CacheService {
  static async saveTasks(tasks: Task[]) {
    const pref = await preferences.getPreferences(getContext(), 'task_cache')
    await pref.put(CACHE_KEY, JSON.stringify(tasks))
    await pref.flush()
  }

  static async loadTasks(): Promise<Task[] | null> {
    const pref = await preferences.getPreferences(getContext(), 'task_cache')
    const data = await pref.get(CACHE_KEY, '')
    if (!data) return null

    const list = JSON.parse(data)
    return list.map(item => new Task(item.id, item.title))
  }
}

📌 Preferences 非常适合:

  • 少量数据

  • 配置

  • 列表缓存


六、第三步:升级 TaskStore(核心改造)

现在轮到 真正的"大脑" ------ Store。

修改 model/TaskModel.ets

复制代码
import { TaskService } from '../service/TaskService'
import { CacheService } from '../service/CacheService'

@ObservedV2
export class TaskStore {
  tasks: Task[] = []
  loading: boolean = false
  error: string = ''

  async loadTasks() {
    this.loading = true
    this.error = ''

    try {
      const remoteTasks = await TaskService.fetchTasks()
      this.tasks = remoteTasks
      CacheService.saveTasks(remoteTasks)
    } catch (e) {
      const cache = await CacheService.loadTasks()
      if (cache) {
        this.tasks = cache
      } else {
        this.error = '加载失败,请检查网络'
      }
    } finally {
      this.loading = false
    }
  }

  addTask(title: string) {
    this.tasks.unshift(new Task(Date.now(), title))
    CacheService.saveTasks(this.tasks)
  }

  removeTask(id: number) {
    this.tasks = this.tasks.filter(item => item.id !== id)
    CacheService.saveTasks(this.tasks)
  }

  get count(): number {
    return this.tasks.length
  }
}

教学重点(非常重要)

  • Store 同时协调

    • 网络

    • 缓存

    • UI 状态

  • UI 只关心三个字段:

    • tasks

    • loading

    • error


七、第四步:页面中触发加载(@Once)

修改 pages/Index.ets

复制代码
@ComponentV2
struct Index {
  @Local store = new TaskStore()

  @Once
  async init() {
    await this.store.loadTasks()
  }

  build() {
    Column({ space: 12 }) {
      Text("📋 我的任务清单")
        .fontSize(22)

      if (this.store.loading) {
        Text("加载中...")
      } else if (this.store.error) {
        Text(this.store.error).fontColor(Color.Red)
      } else {
        Text(`任务数:${this.store.count}`)

        TaskInput({ onAdd: (title) => this.store.addTask(title) })

        TaskList({
          tasks: this.store.tasks,
          onDelete: (id) => this.store.removeTask(id)
        })
      }
    }
    .padding(16)
  }
}

📌 @Once

👉 页面创建时只执行一次

👉 非常适合初始化请求


八、现在这个应用已经进化到什么程度?

你现在的 App 具备了:

✔ 网络请求

✔ Loading 状态

✔ 错误处理

✔ 本地缓存

✔ 离线可用

✔ 状态集中管理

✔ UI 与业务解耦

这已经是正式商用 App 的基础形态


九、如果这是你自己的项目,下一步可以做什么?

🚀 可扩展方向

  1. 下拉刷新(重新调用 loadTasks)

  2. 网络状态监听(自动切换)

  3. 分页加载

  4. 登录态 + Token 缓存

  5. 请求拦截 & 统一错误码

  6. 数据同步策略(本地 → 云)


十、你应该真正学会的不是 API

而是这套思路:

UI 不关心数据从哪里来
Store 决定用网络还是缓存
Service 只做一件事

这是 HarmonyOS、Vue、React、Flutter 通用的工程思维


结语

到这一篇为止,你已经不是"写 Demo"的水平了,而是:

已经在用 HarmonyOS 的正确方式写"真实应用"

相关推荐
柒儿吖4 小时前
GNU make在鸿蒙PC上的使用方法
华为·harmonyos
LRX_1989274 小时前
华为设备配置练习(六)AC 配置
运维·服务器·华为
极客范儿4 小时前
华为HCIP网络工程师认证—MAC地址与网络层
网络·华为
hh.h.4 小时前
轻量集成向:10分钟实现鸿蒙原生工程集成Flutter模块(HAR包导入+跨端通信)
flutter·华为·开源·harmonyos
hh.h.5 小时前
Flutter热重载与鸿蒙原子化服务的动态化革命
flutter·华为·harmonyos
云空5 小时前
《华为汽车架构:全栈智能技术体系》
华为·架构·汽车
叫我龙翔5 小时前
【Redis】从零开始掌握redis --- 认识redis
数据库·redis·缓存
hahjee5 小时前
libxslt XSLT转换库:鸿蒙PC上的XML转换工具
xml·华为·harmonyos
L、2185 小时前
深入实战:使用 Platform Channel 实现 Flutter 与 OpenHarmony 原生能力互通
分布式·flutter·harmonyos