JSI 回调默认跑在 JS 或任务线程上。图形框架、窗口和控件树通常只认 UI 线程。脚本能调到 Native,只说明桥已经通了,并不说明当前线程可以改界面。把这两件事当成一回事,是轻量设备上很常见的问题。
 

  两条线程的职责不一样。JS 线程负责跑脚本、处理模块调用、把参数从脚本世界翻译成 C++;UI 线程负责布局、绘制、动画和控件状态。在 JS 回调里直接改可见性、切换界面资源、启动动画,轻则刷新错乱,重则和正在进行的绘制并发,出现难以复现的竞态。更稳妥的做法是:JSI 里只做参数校验、数据换算和结果打包,真正碰控件或界面管理器的动作,投递到 UI 线程再执行。
 

  投递时要带一份自洽的参数,不要让 UI 线程回头去读 JS 栈上的临时对象。字符串要拷走,结构体在投递前准备好。投递失败,由当前线程回收参数;投递成功,由 UI 线程在执行结束后回收。两边不要同时释放,也不要在投递成功后继续改那块内存。从投递到真正执行之间,页面可能已经退出或状态已变,所以 UI 侧动手前最好再确认一次前提是否仍成立。和界面相关的周期任务、闪烁、翻页,也应留在 UI 线程的任务循环里,不要在 JS 里用定时器去改控件。JSI 的职责是把一次脚本请求变成一次明确的投递,而不是在脚本线程里完成绘制。分清「算什么」和「画什么」,跨语言调用才能在轻量设备上稳定落地。

// 伪代码:JS 线程只投递,UI 线程才改界面
PostToUiThread(RunOnUi, copiedArgs, DeleteArgs);

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐