HarmonyOS 鸿蒙Next页面状态为何未正常同步?

发布于 1周前 作者 phonegap100 来自 鸿蒙OS

HarmonyOS 鸿蒙Next页面状态为何未正常同步?

本人是Flutter开发兼HarmonyOS开发,在按MVVM方案考虑做页面状态管理时遇到了一个百思不得解的问题;

我觉得是我对Harmony状态管理的底层认识出错了,跪求高人解答orz;

测试小组件如下,我发现在实际运行后,日志可以看到计时器的刷新动作,但中间Text中的文本并不会实际刷新;

求大佬解惑!

cke_4280.png

7 回复

【方案一】使用emitter通知testVM所在的struct去更新数据,因为监听的动作只能在组件内,API 10之后class中的this不再指向struct,而[@State](/user/State)的属性监听只能在stauct下才会生效。

注意:emitter只有在真机才会生效,在预览器只会执行一次。

import { hilog } from '@kit.PerformanceAnalysisKit'
import { emitter } from '@kit.BasicServicesKit';
[@Entry](/user/Entry)
[@Component](/user/Component)
struct Page048 {
  [@State](/user/State) testVM: TestVM = new TestVM()
  aboutToAppear(): void {
    emitter.on({ eventId: 1 }, (event) => {
      this.testVM.counter ++
      // this.testVM = JSON.parse(JSON.stringify(this.testVM))
    });
  }
  build() {
    Text(`${this.testVM.counter}`)
  }
}

class TestVM{ counter: number = 0

constructor(){ setInterval(() => {

  <span class="hljs-comment"><span class="hljs-comment">// this.counter++</span></span>
  emitter.emit(
    { eventId: <span class="hljs-number"><span class="hljs-number">1</span></span>, priority: emitter.EventPriority.IMMEDIATE },
    { data: { <span class="hljs-string"><span class="hljs-string">'data'</span></span>: <span class="hljs-number"><span class="hljs-number">33</span></span> } }
  );
  hilog.debug(<span class="hljs-number"><span class="hljs-number">1233</span></span>, <span class="hljs-string"><span class="hljs-string">'TestVM'</span></span>, `<span class="hljs-keyword"><span class="hljs-keyword">new</span></span> count - ${<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.counter}`)
}, <span class="hljs-number"><span class="hljs-number">1000</span></span>)

} } <button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

【方案二】使用@ObjectLink@Observed,但和方案一类似,还是要考虑执行this.counter++时要保证是在struct中调用的,还有就是这种方式写起来比较麻烦,需要@ObjectLink需要写到一个新的组件里,所以代码要抽离出来一个新组件。参考代码如下

import { hilog } from ‘@kit.PerformanceAnalysisKit’

@Component struct Page048Child { @ObjectLink testVM: TestVM

aboutToAppear(): void { this.testVM.start() }

build() { Text(${<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.testVM.counter}) } }

@Entry @Component struct Page048 { @State testVM: TestVM = new TestVM()

build() { Column() { Page048Child({ testVM: this.testVM }) } } }

@Observed class TestVM { counter: number = 0

// constructor(){ start() { setInterval(() => {

  <span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.counter++
  hilog.debug(<span class="hljs-number"><span class="hljs-number">1233</span></span>, <span class="hljs-string"><span class="hljs-string">'TestVM'</span></span>, `<span class="hljs-keyword"><span class="hljs-keyword">new</span></span> count - ${<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.counter}`)
}, <span class="hljs-number"><span class="hljs-number">1000</span></span>)

} } <button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

感谢!大佬,我观察到这些修改,都是保证struct内属性变化是由struct内部的方法发起的,而非内部属性自行更新;用emitter做event响应的方法很灵活,后续业务复杂了进一步拓展也可行

@state装饰的类,其实和类本身有了区别,等于将类加了一个代理,这个代理注册了更新ui的回调。所以,改变类自身的属性,不会触发回调更新ui的,应该是改变代理,也就是改变@state的变量的引用才会触发更新,过程上应该是代理类更新了类的属性,然后触发了回调更新ui。
实际上,可以@state装饰testvm,定义个model,将testvm,set给model,在model异步回来可以更改testvm的值,更新ui

自己摸索了一下,实际需要由Component组件内部方法触发,才可以正常执行子组件的重建方法;

用了一个很丑陋的方案,添加了一个ViewModel的更新回调方法,由struct负责重写,来实现在struct内更新ViewModel组件,能够暂时解决问题;

实不相瞒,楼主还是Android开发菜鸡一个,这种问题很难不联想到Android在更新业务组件UI时需要显式注明runOnUIThread()的要求,即页面渲染的刷新必须在UI线程进行,希望能进一步学习,了解底层逻辑~

image.png

提供的代码不完整,但是你给的[@component](/user/component)自定义组件里面变量可能有点问题,[@state](/user/state)定义的是内部变量,考虑使用[@link](/user/link)和[@state](/user/state)进行父子组件内变量双向同步,可以假如[@provide](/user/provide)设置为必要数据
这个是flutter代码?在鸿蒙里面[@state](/user/state)能监听基础数据,和数组之类的;监听不到自定义的类,需要加[@Observe](/user/Observe)修饰,不知道flutter怎么做

HarmonyOS 鸿蒙Next页面状态未正常同步,可能的原因及解决方案如下:

  1. 状态变量未正确更新:检查是否在页面组件的状态变量更新时存在问题,确保更新操作是在组件内部方法触发,且正确使用了@State@Link等装饰器。
  2. 父子组件同步问题:若涉及父子组件状态同步,需确认是否使用了正确的同步机制,如@Prop用于单向同步,@Link用于双向同步,对于多层关系的组件,可使用@Provide@Consume装饰器。
  3. 异步更新未处理:若状态更新涉及异步操作,需确保异步操作完成后正确更新了状态变量,并触发了UI刷新。
  4. 性能或网络问题:页面状态同步可能受到设备性能或网络状况的影响,优化设备性能和网络环境可能有助于解决问题。

如果以上方法均无法解决问题,可能是系统或框架层面的bug,建议联系官网客服进行进一步排查和解决。官网地址是:https://www.itying.com/category-93-b0.html

回到顶部