HarmonyOS 鸿蒙Next页面状态为何未正常同步?
HarmonyOS 鸿蒙Next页面状态为何未正常同步?
本人是Flutter开发兼HarmonyOS开发,在按MVVM方案考虑做页面状态管理时遇到了一个百思不得解的问题;
我觉得是我对Harmony状态管理的底层认识出错了,跪求高人解答orz;
测试小组件如下,我发现在实际运行后,日志可以看到计时器的刷新动作,但中间Text中的文本并不会实际刷新;
求大佬解惑!
【方案一】使用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响应的方法很灵活,后续业务复杂了进一步拓展也可行
自己摸索了一下,实际需要由Component组件内部方法触发,才可以正常执行子组件的重建方法;
用了一个很丑陋的方案,添加了一个ViewModel的更新回调方法,由struct负责重写,来实现在struct内更新ViewModel组件,能够暂时解决问题;
实不相瞒,楼主还是Android开发菜鸡一个,这种问题很难不联想到Android在更新业务组件UI时需要显式注明runOnUIThread()的要求,即页面渲染的刷新必须在UI线程进行,希望能进一步学习,了解底层逻辑~
HarmonyOS 鸿蒙Next页面状态未正常同步,可能的原因及解决方案如下:
- 状态变量未正确更新:检查是否在页面组件的状态变量更新时存在问题,确保更新操作是在组件内部方法触发,且正确使用了@State、@Link等装饰器。
- 父子组件同步问题:若涉及父子组件状态同步,需确认是否使用了正确的同步机制,如@Prop用于单向同步,@Link用于双向同步,对于多层关系的组件,可使用@Provide和@Consume装饰器。
- 异步更新未处理:若状态更新涉及异步操作,需确保异步操作完成后正确更新了状态变量,并触发了UI刷新。
- 性能或网络问题:页面状态同步可能受到设备性能或网络状况的影响,优化设备性能和网络环境可能有助于解决问题。
如果以上方法均无法解决问题,可能是系统或框架层面的bug,建议联系官网客服进行进一步排查和解决。官网地址是:https://www.itying.com/category-93-b0.html。