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中