一文彻底搞清楚HarmonyOS6.0中的状态管理

43 阅读9分钟

程序员Feri一名13年+的程序员,做过开发带过团队创过业,擅长嵌入式、鸿蒙、人工智能、Java等,专注于程序员成长那点儿事,希望在成长的路上有我相伴!君志所向,一往无前!


ArkUI 状态管理:从 V1 到 V2 的进化之路

在声明式 UI 的世界里,UI 就像是一面镜子,清晰地映射着程序状态的变化。当状态这一 "参数" 发生改变,UI 这面 "镜子" 也会随之呈现新的景象。

在 ArkUI 中,这种因状态变化引发 UI 重新渲染的机制,我们统称为状态管理机制。作为一名深耕技术多年的开发者,今天就带大家深入了解 ArkUI 状态管理的演进历程。

一、状态管理基础:组件渲染的核心驱动力

在 ArkUI 的声明式 UI 编程框架中,View(UI)与 State(状态)构成了一对紧密协作的伙伴。

View 负责将build方法及@Builder装饰方法内的 UI 描述映射到界面,而 State 则是驱动 UI 更新的核心数据。

二者的关系可以形象地比喻为 "演员" 与 "剧本":State 是剧本中的情节发展,View 则是根据情节变化呈现的舞台表演。

(一)@State:组件内状态的 "指挥官"

@State作为组件内状态管理的重要装饰器,就像是一位严格的指挥官,专门用于标记状态变量。

一旦被其标记的变量内容发生改变,对应的 UI 组件(使用了该状态变量)就会像接到命令的士兵一样,立即进行内容更新。

举个简单的例子:

@Entry
@Component
struct StateDemo {
  @State count: number = 0

  build() {
    Column() {
      Text(`点击次数: ${this.count}`)
        .fontSize(20)
      Button("点击我")
        .onClick(() => {
          this.count++
        })
    }
  }
}

在这个示例中,@State装饰的count变量就是状态变量,每次点击按钮改变count的值,UI 都会及时更新显示新的点击次数。

如果不使用@State装饰变量,UI 就只能在初始化时进行一次渲染,后续即使变量值改变,UI 也不会有任何反应,就像一个静止的画面,无法跟随数据的变化而动态更新。

二、状态管理 V1:组件与应用级状态的分层管理

ArkUI 状态管理 V1 提供了丰富的装饰器,这些装饰器就像是不同功能的工具,帮助开发者在不同的场景下管理状态变量。从状态变量的影响范围来看,可分为管理组件内状态的装饰器和管理应用级状态的装饰器。

(一)组件内状态管理:同一组件树的 "信息传递网"

组件级别的状态管理装饰器,如@State、@Prop、@Link等,构建了同一组件树(即同一个页面内)的信息传递网络。

@State用于组件内的状态定义,是组件自身状态的源头;@Prop用于父子组件间的只读单向传递,就像是父亲给孩子传递物品,孩子只能接收而不能修改;@Link则实现了父子组件间的可变更双向传递,如同父子之间的对话,双方都可以对信息进行修改和反馈。

(二)应用级状态管理:跨页面的 "全局信号塔"

应用级别的状态管理装饰器,如@Provide、@Consume等,就像是一座座全局信号塔,能够让状态变量在不同页面,甚至不同 UIAbility 之间传递,实现应用内的全局状态管理。

例如,当我们需要在多个页面共享用户的登录状态时,就可以使用@Provide在父组件中提供状态,然后在子组件中使用@Consume来消费该状态,确保各个页面能够实时获取到最新的登录状态信息。

(三)数据传递形式:单向与双向的 "信息流动"

从数据的传递形式和同步类型层面来看,装饰器可分为只读的单向传递和可变更的双向传递。

单向传递就像是一条单行道,数据只能从一方流向另一方,如@Prop和@Provide-@Consume组合;双向传递则如同双向车道,数据可以在双方之间来回流动,如@Link,这种传递方式在需要父子组件实时交互的场景中非常实用。

三、状态管理 V1 的局限:技术演进的 "导火索"

虽然状态管理 V1 为开发者提供了基本的状态管理能力,但在实际使用中也暴露出了一些问题。

V1 使用代理观察数据,当创建一个状态变量时,同时创建一个数据代理观察者。

这个观察者就像是一个只能看到表面现象的观察者,它只能感知代理的变化,却无法洞察实际数据的深层变化,从而带来了一系列限制:

(一)状态与 UI 的 "强绑定"

状态变量不能独立于 UI 存在,就像是被 UI 紧紧束缚的舞者,无法在更广阔的舞台上发挥作用。

当同一个数据被多个视图代理时,在其中一个视图的更改不会通知其他视图更新,就像多个舞者各自按照自己的节奏跳舞,却无法同步动作。

(二)浅层观测的 "视力缺陷"

只能感知对象属性第一层的变化,对于深层的属性变化视而不见,存在 "视力缺陷"。

例如,当一个对象的嵌套属性发生改变时,V1 无法及时检测到这种变化,导致 UI 不能及时更新,就像一个视力不好的人只能看到眼前的景象,却看不到远处的细节。

(三)冗余更新的 "资源浪费"

在更改对象中属性以及更改数组中元素的场景下,会出现冗余更新的问题,就像是一个不精准的指挥官,下达了过多不必要的命令,浪费了系统资源。

(四)装饰器配合的 "复杂谜题"

装饰器间配合使用限制多,不易用,就像是一堆复杂的拼图,很难找到合适的组合方式。

组件中没有明确状态变量的输入与输出,不利于组件化开发,就像一个没有明确分工的团队,协作起来困难重重。

四、状态管理 V2:数据驱动的 "深度进化"

为了克服 V1 的局限,ArkUI 推出了状态管理 V2,这是一次从代理观察到数据本身观察的重大进化。

在 V2 中,数据本身成为了可观察的主体,就像是拥有了自我表达能力的演员,每一个细微的变化都能被精准捕捉。

(一)V2 的核心优势:数据驱动的 "精准打击"

状态独立:自由舞动的 "数据精灵"

状态变量不再依赖于 UI,可以独立存在,就像一个自由舞动的数据精灵,在不同的视图之间传递信息。当数据发生更改时,会精准地触发相应视图的更新,而不是像 V1 那样受限于 UI 的绑定。

深度观测:洞察秋毫的 "数据侦探"

支持对象的深度观测和深度监听,能够像侦探一样敏锐地捕捉到对象深层属性的变化,而且深度观测机制不会影响观测性能,确保在复杂数据结构下也能高效运行。 精准更新:节约资源的 "高效引擎"

支持对象中属性级精准更新及数组中元素的最小化更新,就像是一个高效的引擎,只对发生变化的部分进行更新,避免了冗余更新,大大提高了系统性能。

易用拓展:组件化开发的 "得力助手"

装饰器易用性高、拓展性强,在组件中明确了状态变量的输入与输出,就像是给团队成员明确了分工,有利于组件化开发,提高开发效率和代码的可维护性。

(二)V2 的实际应用:复杂场景的 "解决方案"

以一个复杂的对象数据结构为例,假设我们有一个包含嵌套对象和数组的状态数据:

class ComplexData {
  name: string = "张三"
  age: number = 25
  hobbies: string[] = ["编程", "阅读"]
  address: {
    city: "北京",
    district: "朝阳区"
  } = { city: "北京", district: "朝阳区" }
}

在 V1 中,当我们修改address.district或者hobbies中的某个元素时,由于只能进行浅层观测,会导致整个对象对应的 UI 组件重新渲染,造成冗余更新。

而在 V2 中,借助其深度观测和精准更新的能力,只会对发生变化的属性或数组元素对应的 UI 部分进行更新,大大提高了渲染效率。

五、总结:选择适合的状态管理方案

ArkUI 状态管理从 V1 到 V2 的演进,是技术不断优化和完善的过程。

V1 适用于一些简单的应用场景,能够满足基本的状态管理需求;而 V2 则在处理复杂数据结构、大型项目开发以及追求高效性能的场景中表现更为出色。

作为开发者,我们需要根据项目的实际需求选择合适的状态管理方案。

在小型项目或简单组件中,V1 的装饰器可能已经足够;但在大型复杂项目中,V2 的深度观测、精准更新和易用性等优势将发挥重要作用。

好啦,关于 ArkUI 状态管理的内容就先介绍到这里。

如果大家想考取鸿蒙开发者认证的,欢迎加入我的专属考试链接中:developer.huawei.com/consumer/cn…

后续我会持续更新状态管理涉及到的组件相关装饰器的具体应用,包括@State、@Prop、@Link、@Provide、@Consume等在不同场景下的使用技巧和最佳实践。

关注我,一起在程序员成长的道路上稳步前行,探索更多技术的奥秘!