任何事物都有其产生、发展和灭亡的过程。Page和AbilitySlice也不例外。以Page为例,用户可以启动一个Page,也可以关闭一个Page。被打开的Page可能会被另一个Page全部或部分遮挡,此时被遮挡的Page就不能响应UI事件。当用户进入桌面时,被打开的应用程序的Page会进入后台。总之,一个Page被启动后可能会被用户各种“折腾”,并最终被关闭。从一个Page(AbilitySlice)启动到关闭的全部过程就是一个Page(AbilitySlice)的生命周期(Lifecycle)。由于Page和AbilitySlice都具有承载用户界面的功能,并且其生命周期的方法非常类似,因此下文一并进行介绍。
Page(AbilitySlice)包括4种生命周期状态:
(1)初始态(INITAL):当Page(AbilitySlice)还没有被启动时,以及Page被关闭后就会处于初始态。
(2)非活跃态(INACTIVE)是指Page(AbilitySlice)已经启动,但是此时可能因为被对话框遮挡一部分界面等情况,无法进行用户交互,此时为非活跃态。
(3)活跃态(ACTIVE)是指在Page(AbilitySlice)处于界面的最前台,正在与用户进行交互,此时为活跃态。
(4)后台态(BACKGROUND)是指Page(AbilitySlice)完全不可见的状态。此时,可能被其他的Page(AbilitySlice)完全遮挡,或者应用程序已经进入后台(用户按下Home键进入桌面或者正在熄屏)。
当生命周期状态被切换时,系统会回调到生命周期方法中以便处理一些必要的事务。例如,当AbiltySlice从初始态切换到非活跃态时,需要进行UI界面的初始化;当AbilitySlice进入后台态时,如果此时正在播放视频,可能需要将视频暂停。准确地应用生命周期方法进行界面和业务逻辑的控制有助于提高应用程序的设计感、稳健性和流畅性。
Page(AbilitySlice)的生命周期方法如下:
(1)onStart(Intent intent):当Page(AbilitySlice)从初始态进入非活跃态时,即启动Page(AbilitySlice)时触发,在整个生命周期中仅被触发1次。
(2)onActive():当Page(AbilitySlice)从非活跃态进入活跃态时触发。
(3)onInActive():当Page(AbilitySlice)从活跃态进入非活跃态时触发。
(4)onBackground():当Page(AbilitySlice)从非活跃态进入后台态,即完全不可见时触发。
(5)onForeground(Intent intent):当Page(AbilitySlice)从后台态进入非活跃态,即重新可见时触发。
(6)onStop():当Page(AbilitySlice)从后台态进入初始态时,即结束Page(AbilitySlice)时触发,在整个生命周期中仅被触发1次。
Page(AbilitySlice)的整个生命周期状态及状态切换时所调用的生命周期方法如图3-11所示。
图3-11 Page(AbilitySlice)的生命周期
使用生命周期方法时需要注意以下几个方面:
(1)在一个Page(AbilitySlice)的整个生命周期中,一定会回调onStart、onActive、onInactive、onBackgroud和onStop方法,而只有onForeground方法并不一定被回调。
(2)在Page(AbilitySlice)处在后台态时(即完全不可见时),并且出现了内存不足等情况,Page(AbilitySlice)可能会被系统直接回收。
(3)开发者需要把握各个业务逻辑的正确时机。例如,在onStart方法中需要进行UI界面的初始化;在onStop方法中需要检查并关闭所有由本Page(AbilitySlice)打开的数据库连接等。一些常用业务逻辑的调用时机会在今后的学习中逐步介绍,当然对于特殊的业务逻辑则需要开发者自行设计。
接下来,我们通过实例深入体验一下Page和AbilitySlice的生命周期。
首先,创建一个新的名为Lifecycle的应用程序,专门对生命周期方法进行学习及调试使用。与第2章所创建的HelloWorld类似,这个Lifecycle工程选择目标设备仍然为Wearable,并使用Empty Feature Ability(Java)模板。
然后,修改MainAbility类,实现所有的6个生命周期方法,并在每个生命周期方法被调用时打印其生命周期方法的名称,代码如下:
与MainAbility类似,实现MainAbilitySlice的6个生命周期方法,并在调用时打印其生命周期方法的名称,代码如下:
注意,为了区分打印输出的来源,在MainAbility类和MainAbilitySlice类中,HiLogLabel的tag参数不同,前者为MainAbility,而后者为MainAbilitySlice。
编译并在虚拟机中运行Lifecycle应用程序,设备出现MainAbilitySlice界面。在这个过程中,HiLog工具窗体依次显示以下提示(此处略去了提示时间,下同):
这说明在进入MainAbilitySlice界面的过程中,MainAbility和MainAbilitySlice从初始态进入了非活动态,紧接着又从非活动态进入了活动态。并且,在每次的状态变化时,MainAbility都要先于MainAbilitySlice一步。
接下来,在虚拟机中单击 (Home)按钮进入桌面,同时应用程序进入后台,MainAbility和MainAbilitySlice不可见。在这个过程中,HiLog工具窗体依次显示以下提示:
这说明,MainAbility和MainAbilitySlice从活动态进入了非活动态,紧接着又从非活动态进入了后台态。
然后,再次返回到该应用程序,HiLog工具窗体依次显示以下提示:
这说明,MainAbility和MainAbilitySlice从后台态进入了非活动态,紧接着又从非活动态进入了活动态。
如果此时单击模拟器的 (Back)按钮退出应用程序,HiLog工具窗体依次显示以下提示:
这说明,MainAbility和MainAbilitySlice从活动态进入了非活动态,紧接着又从非活动态进入了后台态,最后又从后台态进入了初始态。
这些调用过程非常重要,开发者一定要时刻注意其状态的变化。接下来,总结一下常见的生命周期状态的变化过程,如表3-1所示。
表3-1 常见的生命周期状态变化过程
另外,因为Page是AbilitySlice的载体,所以Page的生命周期总是先于AbilitySlice一步。
上面演示的仅为单个的Page,而且Page中仅有单个的AbilitySlice时的生命周期变化情况。事实上,不仅Page之间可以跳转,同一个Page内的AbilitySlice也可以跳转。当同一个Page内的AbilitySlice跳转时,Page的状态一直处于活动态,而AbilitySlice的生命周期却在发生变化。
例如,某一个Page中存在两个AbilitySlice,分别为SliceA和SliceB。当从SliceA跳转到SliceB时,两者的生命周期状态变化过程如下:SliceA从活动态转换为非活动态→SliceB从初始态转换为非活动态→SliceB从非活动态转换为活动态→SliceA从非活动态转换为后台态。生命周期的调用顺序如下:SliceA.onInactive()→SliceB.onStart()→SliceB.onActive()→SliceA.onBackground()。
在Page或AbilitySlice中,通过getLifecycle().getLifecycleState()方法即可获得当前的生命周期状态。生命周期状态通过Lifecycle.Event枚举类型定义,其所有枚举值包括UNDEFINED、ON_START、ON_INACTIVE、ON_ACTIVE、ON_BACKGROUND、ON_FOREGROUND、ON_STOP。
例如,在Page或AbilitySlice中通过这种方法即可打印出当前的生命周期状态,代码如下: