Wms切换acitivity的窗口 - l-feng/l-feng.github.io GitHub Wiki

Wms切换窗口的实质是:在前一个激活的activity组件进入到pause状态并且激活的activity

组件进入到resumed状态之后,将前一个激活的activity组件的窗口设置为不可见,以及将新

激活的窗口设置为不可见的过程activityManagerService服务在启动一个activity组件的

过程中会调用到activityStack类的成员变量函数startActivitylocked,activityStack类

的成员函数startActivityLocked首先会给正在启动的activity组件准备一个切换动作,接着

在调用其他的成员函数来通知前一个激活的activity组件进入到pause状态,等到前一个组件

进入到pause状态之后,AMS的服务就会来检查正在启动的activity启动了没有,如果没有,

那么AMS服务就会将该程序启动,然后在调用ActivityStack类的成员变量realStartActivityLocked

来将正在启动的activity组件加载起来,并且在它的状态设置为resumed,然后通知wms服务执行前面的切换操作

。 startActivityLocked()-------->prepareAppTranstion()------------->realStartActivitylocked()------>

setAppVisibility()---------->completeResumedLocked()------------------>ensureActivitiesVisibleLocked()---------

executAppTranstion()------------------->performLayoutAndPlaceSurfaceLocked()--------------------

performLayoutAndPlaceSurfaceLockedInner()

主要分为两部分:

(1)prepareAppTranstion:准备Activity切换动画操作

(2)executeAppTranstion:执行Activity切换动画操作

一:Activity切换动画

activityStack.startActivityLocked()代码

.............................. (1)如果启动的intent里面传入了intent.flag_activity_no_animaton标志,则表示该activity不执行切换动画。

(2)否则,调用wms.prepareAppTranstion执行了一个AppTranstion.Transit_activity_open或者

AppTranstion.Transit_task_open类型的动画,

Wms.prepareApptransition()代码

.......................................

前期工作主要是appTranstion.mNextAppTranstion全局变量保存activity切换的动画类型

二:executeAppTranstion动画

前一个activity进入到paused状态之后,客户端通过AMS自己进入到paused状态,并重新回调到

ActivityStack.resumeTopActivityInnerLocked()在调用startSpecificActivityLocked()

启动新的acitvity之后,会做两件事:

1:将当前最新的Activity在AMS对应的ActivityRecord.visible设置为true,代表该activity

需要在屏幕上显示出来。Next.visible=true。 2:调用ActivityStackSupervisor.reportResumeActivityLocked执行切换动画的操作及调用

AMS.setFoucedActivityLocked切换焦点,简单来说,切换焦点。

切换焦点主要做以下几件事:

1:将当前启动新的activity保存在ActivityRecord.mFoucusedActivity全部变量中

2:调用activityStackSupervisor.setFocusedStack对activity任务栈进行调整

3:调用WMS.setFocusedApp更新WMS的焦点窗口。

setFocusedApp代码

       ......................................

可以看出WMS更新焦点窗口主要做了下面的几件事:

1:通过mfocusedApp保存焦点窗口

2:调用inputMonitor.setFocusetAppLw()更新inputService输入系统中的焦点窗口

3:调用updateFocusedWindowLocked()更新phoneWindowManager()的焦点窗口对象,并通过

客户端ViewRootImpl焦点窗口发生改变

updateFocusedWindowLocked代码

.....................................

可以看到先通过AppWindowToken.mFocusedApp找到对应的焦点窗口WindowState,保存在全局变量

mCurrentFocus中,然后发送H_Report_Focus_change.消息给ViewRootImpl更新窗口,在调用

phoneWindowManager.focuschangeLw()更新mFocusedWindow并且调用updateSystemvisibilityLw

来重新计算系统ui的可见性。如果发送了变化的话,则会发送finish_Layout_redo_Layout

fousedChangeLw()的代码

......................................

在updatefocusedWindowLocked()方法中,会进行判断,如果输入法窗口焦点改变或者系统ui发生

可见性变化,都会再次调用performLayoutLockedInner方法发起一次重新布局、而发生Report_focus_change

消息通知客户端焦点窗口发生改变,主要是通过WindowState.reportFocusChangedSerialized方法完成,

里面主要调用mClient.windowFocusChanged();这样就走到了ViewRootImpl.WindowFocusChanged方法里面

可以看到焦点窗口的改变ActivityManagerService.setFocsedActivityLocked发起,但是会去更新的地方很多。

AMS------>WMS--------------->phoneWindowManager------------->ViewRootImpl

焦点窗口的改变分析完之后,我们又重新回到ActivityStack.setfocusedActivityLocked之后,

继续Activity窗口的切换,里面最关键的操作就是焦点窗口更新前调用了

ActivityStackSuperVisor.reportResumedActivityLocked()

reportResumedActivityLocked()函数代码

..................................

在reportResumedActivityLocked函数里面主要做了两件事情 1:onsureActivitiesVisiblelocked()调用了activityStack类的成员函数

ensureActivitiesVisibleLocked,从上到下检查哪些activity组件是设置为可见的,

哪些acitivity组件是需要设置不可见的。主要方法是通过从上到下找到一个全屏显示的activity组件

上面的activity组件上面的其他activity组件的可见性设置为true,而通过ActivityRecord.fullScreen

成员变量可以来判断当前activity是否全屏

2:调用wms.executeAppTransition来执行准备好的activity的切换动画

executeAppTransition()代码

....................................

首先是判断如果mNextAppTranstion!=Transit_unset,就会设置mAppTransitionState=app_state_ready,

并且调用performLayoutAndPlaceSurfaceLocked()来发起wms中的窗口布局以及动画操作,由于我们在前面

prepareAppTransition准备动画时,AppTransition.mNextAppTransition值根据启动activity不同情况设置为

AppTransition.Transit_Task_Open或者appTransition.Transit_activity_open所以

mNextAppTransition!=Transit_unset这个条件可以满足首先会判断mAppTransitionstate=app_state_ready

是否成立,由分析可知道,这个是成立的,然后就会调用handleAppTransitionReadyLocked里面会通过AppWindowToken.allDrawn

来判断一个activity窗口所有的控件是否绘制完毕,如果是的话,才开始后面的动画切换动画,最后就会调用setTokenVisiblityLocked,

这个函数是activity窗口设置动画的关键。

setTokenVisibilityLocked代码

. .........................................

在setTokenVisibilityLocked里面主要做了两件事:

1:设置activity切换动画,WMS.applyAnimationLocked()

2: 设置acitivity窗口进入动画,WMS.applyAnimationLocked()

在WMS.applyAnimationLocked方法会调用appTransiton.loadAnimation方法。第二个传参就是

前面prepareAppTransition准备动画中通过Apptransition.mNextAppTransition保存的动画类型。

为桌面创建一个Task来启动一个activity时,切换动画类型为AppTransition.Transit_task_open,

当是在同一个Task中,启动一个activity时候,切换动画类型为Transition.transit_activity_open.

1:appTransition.Transit_task_open

启动一个应用的activity切换动画是沿着Y轴从屏幕下方出来

2:appTransition.Transit_activity_open

可以看到应用界面切换activity的动画沿着Z轴方向从右到左滑入的

当应用自己调用系统接口设置切换动画后,它的优先级是最高的,就不会再去使用系统动画资源了,

比如观察短信新建界面,它是从下往上拉起一个动画的,没有使用系统的动画资源,那是因为短信

在代码中自己设置了切换动画最后在WMS.applyAnimatonLocked()的结尾,会把这个activity切换

动保存在当前窗口,Wtoken.AppWindowToken.animation中