简介
HarmonyOS涉及的启动模式,就是Android中的那个启动模式,一样的概念。它指的是一个UIAbility实例,被打开的时候,如果已经存在了UIAbility,是复用上一个呢,还是重新创建一个呢, 如果复用的话,那窗口行为应该是什么呢。 模式就是来指定这些行为的。
在HarmonyOS中启动模式被简化成了三种
- 单例模式 singleton
- 多实例模式 multiton
- 指定实例模式 specified
设置方式
在module.json5文件中找到相应的UIAbility配置项,设置lanchType参数
{"module": {// ..."abilities": [{"launchType": "singleton",// ...}]}
}
singleton启动模式
singleton模式是单例模式,是默认情况下的应用启动模式。
它的表现是,每当开启一个UIAbility的时候,如果发现系统里存在一个一样的UIAbility,则就不进行创建实例直接复用。
我们前面已经学到,一个UIAbility对标的是一个任务管理器中的任务,这里跟Android的Activity还是存在区别的。如果一个HarmonyOs应用里面存在多个UIAbility,并且全部打开了,当用户退出界面选择任务列表的时候,您会发现存在很多任务,这原则上讲是很乱的。所以HarmonyOs的默认模式为singleton是有道理的。
如图所示,存在两个UIAbility,您的列表就是两个。非必要不要这个样子。
注意事项
应用的UIAbility实例已创建,该UIAbility配置为单实例模式,再次调用startAbility()方法启动该UIAbility实例。由于启动的还是原来的UIAbility实例,并未重新创建一个新的UIAbility实例,此时只会进入该UIAbility的onNewWant()回调,不会进入其onCreate()和onWindowStageCreate()生命周期回调。
multiton启动模式
又称为多实例启动模式,这个的表现是每次开启一个UIAbility,系统不会查看系统中有没有已有的实例对象,直接就是创建,全部都是新的,也就是走全生命周期流程。当然此时如果频繁的创建,您在任务列表中。
这么乱什么时候会用到呢?
有个场景是,您写的App,必须要两个界面同时都在,这样才能使得用户体验良好的情况下,它就适合,比如,微信聊天,开着视频,要么小窗,要么就开俩大窗。就是涉及多窗口的情况下需要用到这个。另外对于一些跨设备协同的情景也需要这个。
specified启动模式
specified指定实例模式。可以理解为一个可以复用的意图模式。总共分为两大特点
- 它的开启,需要在调用方传入意图信息,还记得onCreate()函数中有一个叫want的参数么?就是和这个有关的。
- 它一旦被开启,除非实例被销毁掉,当下次用户再打开同样的调用时,传入同样的内容,便会像singleton模式那样进行复用。
举个例子:
文档应用中每次新建文档希望都能新建一个文档实例,重复打开一个已保存的文档希望打开的都是同一个文档实例。这个现象在电脑中很常见。
对于那些被定义为specified的UIAbility,这就有点参与招标的企业乙方,甲方投标,如果乙方的要求都符合,可以参与招标,全都符合比较满意就中标。
对于调用方而言,也就是甲方,首先会拿到当下功能需要的特征(意图),然后根据这个意图,而选择开启哪个响应这种意图的UIAbility。如果这个UIAbility存在的话,就复用,不走onCreate流程,回调onNewWant()。如果不存在,就会创建一个实例,走生命周期。
如图所示,假设UIAbilityA是开启方,UIAbilityB是被开启方,且模式是specified。
其中KEY,是识别出是否存在符合的Activity的核心。我们用代码体会一下这些逻辑片段,看看是怎么利用它的。
1 首先我们先给UIAbilityB进行设置,来说明这是一个指定实例模式。
{"module": {// ..."abilities": [{"launchType": "specified",// ...}]}
}
2 对于开启方UIAbilityA而言,当打开UIAbilityB的时候,设置代码如下
let context : common.UIAbilityContext = getContext(this) as common.UIAbilityContext
let want : Want = {deviceId : '', //空字串代表是本设备,意味着,别的设备也行。bundleName: 'com.samples.stagemodelabilitydevelop', //bundle之前提到过,涉及到的所有模块包合起来形成一个bundleabilityName : 'UIAbilityB',moduleName : 'entry', //entry包,符合bundle的特点,可以包含许多模块包parameters : {instanceKey : this.KEY_NEW //自定义的值}context.startAbility(want).then(()=> {hilog.info(DOMAN_NUMBER, TAG, 'Successed in starting UIAbilityB')})
}
3 当UIAbilityA在开启时,会检索系统中有没有符合标准的UIAbilityB,如果有,会回调UIAbility的onNewWant()函数。那么我们应该做的是在AbilityStage文件中,这个回调里做相应的逻辑。
onAcceptWant(want: Want): string {// 在被调用方的AbilityStage中,针对启动模式为specified的UIAbility返回一个UIAbility实例对应的一个Key值// 当前示例指的是module1 Module的SpecifiedAbilityif (want.abilityName === 'UIAbilityB') {// 返回的字符串KEY标识为自定义拼接的字符串内容if (want.parameters) {return `SpecifiedAbilityInstance_${want.parameters.instanceKey}`;}}// ...return 'MyAbilityStage';}
4 当UIAbilityB被调用之后,如果以后再有机会调用,那么UIAbilityB会被复用,马上回调onForground() . 所以一旦匹配上就会开一个窗口,除非匹配不上key,会开启一个新的UIAbilityB的窗口,并将Key记录住。我们看步骤3出处也会发现,匹配实则是一个严格匹配。返回的字符串,就是为了系统管理映射,有的话,找老的实例回复,没有的话,就新建一个。