HarmonyOS 7 Window Kit + UIAbility 实战:应用内分屏、多窗口与状态隔离设计

折叠屏、平板、PC 上跑原来的手机 App,状态串了、布局歪了、数据同步了——问题都出在还是单窗口思维。

文章封面

最开始做应用的时候,默认就是手机单窗口:一个 UIAbility 实例,一个当前页面,一套全局状态。在手机上跑没问题,一切正常。

后来要适配折叠屏和平板,才发现问题来了:分屏之后两个窗口同时在跑,原来写的全局状态直接串了——在左窗口改了数据,右窗口也跟着变了。布局也不对,原来按竖屏尺寸写的固定高度,横屏分屏之后直接变形。

这时候才意识到:多窗口不是"把布局拉宽"那么简单,是整个应用架构都要从单窗口思维转过来。

一、响应式布局和真正的多窗口不是一回事

先把两个概念区分清楚:

类型特点本质
响应式布局一个窗口,根据尺寸变布局还是单实例
应用内分屏一个 App 开两个窗口实例多实例多状态

响应式布局只是同一个窗口里,布局从单栏变成双栏。但应用内分屏是真的开了两个 UIAbility 实例,每个实例有自己的生命周期、自己的页面栈、自己的状态。

很多人最开始把多窗口理解成"用 Row 左右分两栏",那就完全错了。Row 双栏还是同一个页面实例,共享同一套状态。但真正的多窗口是两个独立的实例。

二、窗口实例和 UIAbility 的关系

每个窗口对应一个 UIAbility 实例。你开了两个窗口,就是两个 UIAbility 实例,跑在同一个进程里。

窗口类型UIAbility 实例页面栈状态
单窗口1 个1 个 NavPathStack全局共享
应用内分屏2 个2 个 NavPathStack各自独立
多实例N 个N 个 NavPathStack各自独立

这就是为什么原来的全局状态会串:所有 UIAbility 实例都引用同一个全局状态对象。左窗口改了数据,右窗口自然也跟着变了。

三、StartOptions 怎么控制窗口创建

打开新窗口的时候,通过 StartOptions 指定窗口模式和参数。

这段代码解决什么问题: 以分屏模式打开新的页面实例。
文件: pages/HomePage.ets
用途: 多窗口启动
接入位置: 点击"在新窗口打开"按钮

import window from '@ohos.window';
import UIAbility from '@ohos.app.ability.UIAbility';

async openSplitWindow() {
  const context = getContext(this);
  const want = {
    bundleName: 'com.example.app',
    abilityName: 'EntryAbility',
    parameters: { windowMode: window.WindowMode.WINDOW_MODE_SPLIT, page: 'detail' }
  };
  context.startAbility(want, { windowMode: window.WindowMode.WINDOW_MODE_SPLIT });
}

这里指定了窗口模式是分屏,同时通过 Want 传了要打开的页面参数。新窗口启动之后,会走自己的 onCreate 生命周期,创建自己的页面栈。

四、为什么 NavPathStack 不能全局共享

这是多窗口最容易踩的坑。

原来单窗口的时候,把 NavPathStack 做成全局单例,所有页面都用同一个导航栈。在单窗口下没问题,因为只有一个页面。

但多窗口下,两个 UIAbility 实例都引用同一个全局 NavPathStack,那左窗口 push 了一个页面,右窗口的页面栈也跟着变了。导航完全乱套。

正确的做法是:每个 UIAbility 实例持有自己的 NavPathStack。全局状态里不要放导航栈,要按窗口实例分开管理。

模块关系图

五、全局状态和局部状态怎么隔离

状态类型多窗口下的处理
用户登录态可以全局共享(同一个账号)
页面表单数据必须局部隔离(每个窗口各填各的)
列表选中项必须局部隔离
缓存的临时数据按窗口实例隔离
应用配置可以全局共享

原则很简单:和"当前哪个窗口"有关的状态,必须局部隔离;和"应用整体"有关的状态,可以全局共享。

六、窗口销毁的时候要释放什么

多窗口下还有个容易忘的点:窗口销毁的时候,对应的监听器、定时器、订阅都要释放。

单窗口的时候应用退出才释放,问题不大。但多窗口下,用户关掉其中一个窗口,另一个窗口还在跑。如果销毁的那个窗口的监听器没释放,它还在后台跑,占着内存,甚至还在更新 UI——但 UI 已经没了。

窗口销毁的时候要检查:

  • 窗口变化监听器有没有移除;
  • 定时器有没有清掉;
  • 事件订阅有没有取消;
  • 持有的资源有没有释放。

七、测试的时候不能只测 1:1 分屏

很多人测多窗口就测一下 1:1 分屏,觉得没问题就上线了。但实际场景里分屏比例是可以拖的——1:2、2:1、甚至更小的窗口。

测试场景检查点
1:1 分屏基础布局正常
1:2 分屏窄窗口下布局不挤
2:1 分屏宽窗口下布局不松
悬浮窗小尺寸下内容不溢出
折叠屏展开/收起状态不丢失

尤其是折叠屏展开收起的时候,窗口尺寸会变。这时候要保证页面状态不丢,布局能自适应调整。

运行效果图

这次做多窗口适配最大的体会是:多窗口不是布局问题,是架构问题。原来的单窗口思维——一个全局状态、一个导航栈、一套页面——在多窗口下全都要拆开。哪一层没拆干净,哪一层就出问题:状态串了、导航乱了、资源漏了。想清楚"哪些状态是窗口级的、哪些是应用级的",再动代码。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值