Android窗口管理服务WindowManagerService切换Activity窗口App Transition的过程分析.docx
- 文档编号:27752621
- 上传时间:2023-07-04
- 格式:DOCX
- 页数:55
- 大小:120.85KB
Android窗口管理服务WindowManagerService切换Activity窗口App Transition的过程分析.docx
《Android窗口管理服务WindowManagerService切换Activity窗口App Transition的过程分析.docx》由会员分享,可在线阅读,更多相关《Android窗口管理服务WindowManagerService切换Activity窗口App Transition的过程分析.docx(55页珍藏版)》请在冰豆网上搜索。
Android窗口管理服务WindowManagerService切换Activity窗口AppTransition的过程分析
Android窗口管理服务WindowManagerService切换Activity窗口(AppTransition)的过程分析
在Android系统中,同一时刻只有一个Activity组件是处于激活状态的,因此,当ActivityManagerService服务激活了一个新的Activity组件时,它就需要通知WindowManagerService服务将该Activity组件的窗口显示出来,这会涉及到将焦点和屏幕等资源从前一个激活的Activity组件切换到后一个激活的Activity组件的过程,本文就详细分析这个过程。
Activity窗口的切换操作是在新激活的Activity组件的启动过程进行的。
具体来说,就是在前一个激活的Activity组件进入到Paused状态并且新激活的Activity组件进之到Resumed状态之后,将前一个激活的Activity组件的窗口设置为不可见,以及将新激活的Activity组件的窗口设置为可见。
整个切换过程是需要在ActivityManagerService服务和WindowManagerService服务的协作之下进行的,如图1所示。
WindowManagerService服务在执行Activity窗口的切换操作的时候,会给参与切换操作的Activity组件的设置一个动画,以便可以向用户展现一个Activity组件切换效果,从而提高用户体验。
事实上,一个Activity窗口在由不可见状态切换到可见状态的过程中,除了会被设置一个Activity组件切换动画之外,还有被设置一个窗口进入动画,此外,如果该Activity窗口是附加在另外一个窗口之上的,并且这个被附加的窗口正在显示一个动画,那么这个动画也同时会被设置给到该Activity窗口的显示过程中去。
本文主要是关注Activity窗口的切换操作,在接下来的一篇文章中分析窗口的动画框架时,我们再详细分析上述三种动画是如何作用在窗口的显示过程中的。
从前面一文可以知道,ActivityManagerService服务在启动一个Activity组件的过程中,会调用到ActivityStack类的成员函数startActivityLocked。
ActivityStack类的成员函数startActivityLocked首先会给正在启动的Activity组件准备一个切换操作,接着再调用其它的成员函数来通知前一个激活的Activity组件进入到Paused状态。
等到前一个激活的Activity组件进入到Paused状态之后,ActivityManagerService服务就会检查用来运行正在启动的Activity组件的进程启动起来了没有。
如果这个进程还没有启动,那么ActivityManagerService服务就会将该进程启动起来,然后再调用ActivityStack类的成员函数realStartActivityLocked来将正在启动的Activity组件加载起来,并且将它的状态设置为Resumed,最后通知WindowManagerService服务执行前面所准备的切换操作。
接下来,我们就从ActivityStack类的成员函数startActivityLocked开始分析Activity窗口的切换过程,如图2所示。
这个过程可以分为9个步骤,接下来我们就详细分析每一个步骤。
Step1.ActivityStack.startActivityLocked
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
publicclassActivityStack{
......
privatefinalvoidstartActivityLocked(ActivityRecordr,booleannewTask,
booleandoResume){
finalintNH=mHistory.size();
intaddPos=-1;
if(!
newTask){
//Ifstartinginanexistingtask,findwherethatis...
......
}
//Placeanewactivityattopofstack,soitisnexttointeract
//withtheuser.
if(addPos<0){
addPos=NH;
}
......
//Slottheactivityintothehistorystackandproceed
mHistory.add(addPos,r);
......
if(NH>0){
......
if((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION)!
=0){
mService.mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
......
}elseif((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)!
=0){
mService.mWindowManager.prepareAppTransition(
WindowManagerPolicy.TRANSIT_TASK_OPEN);
......
}else{
mService.mWindowManager.prepareAppTransition(newTask
?
WindowManagerPolicy.TRANSIT_TASK_OPEN
:
WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
......
}
......
}
......
if(doResume){
resumeTopActivityLocked(null);
}
}
......
}
这个函数定义在文件frameworks/base/services/Java/com/android/server/am/ActivityStack.java中。
参数r描述的是正在启动的Activity组件,ActivityStack类的成员函数startActivityLocked首先找到它在Activity组件堆栈中的位置addPos,即找到它在ActivityStack类的成员变量mHistory所描述的一个ArrayList中的位置,然后再将正在启动的Activity组件保存在该位置中。
变量NH描述的是将参数r描述的是正在启动的Activity组件保存在Activity组件堆栈前系统已经启动了的Activity组件的个数。
只有在这个变量的值大于0的情况下,系统才需要执行一个Activity组件切换操作。
也就是说,如果参数r描述的是正在启动的Activity组件是系统中第一个启动的Activity组件,那么就不需要执行一个Activity组件切换操作了。
注意,即使参数r描述的是正在启动的Activity组件不是系统中第一个启动的Activity组件,那么系统也可能不需要执行一个Activity组件切换操作,因为用来启动参数r所描述的一个Activity组件的一个Intent对象的成员函数getFlags返回的一个标志值的Intent.FLAG_ACTIVITY_NO_ANIMATION位可能会不等于0,这意味着正在启动的Activity组件不需要显示切换动画。
在这种情况下,ActivityManagerSerivce服务就会通知WindowManagerService服务不需要准备一个Activity组件切换操作,这是通过以WindowManagerPolicy.TRANSIT_NONE为参数来调用ActivityStack类的成员变量mService所指向的一个ActivityManagerService对象的成员变量mWindowManager所描述的一个WindowManagerService对象的成员函数prepareAppTransition来实现的。
另一方面,如果参数r描述的是正在启动的Activity组件不是系统中第一个启动的Activity组件,并且系统需要执行一个Activity组件切换操作,即需要WindowManagerService服务在显示正在启动的Activity组件的窗口时应用一个切换动画,那么这个动画的类型也是有讲究的。
具体来说,如果参数r描述的是Activity组件是需要在在一个新的任务中启动的,即参数newTask的值等于true,那么切换动画的类型就指定为WindowManagerPolicy.TRANSIT_TASK_OPEN,否则的话,切换动画的类型就指定为WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN。
此外,如果用来启动参数r所描述的一个Activity组件的一个Intent对象的成员函数getFlags返回的一个标志值的Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET位不等于0,那么也会将切换动画的类型设置为WindowManagerPolicy.TRANSIT_TASK_OPEN。
Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET这个标志位等于1意味着当参数r所描述的一个Activity组件所在的任务下次作为前台任务来运行时,参数r所描述的Activity组件以及它上面的并且属于同一个任务的其它Activity组件都会被结束掉,以使得位于参数r所描述的Activity组件的前面一个Activity组件可以显示出来。
例如,如果我们正在使用一个EmailActivity组件来查看Email,这时候又需要启动另外一个PictrueActivity来查看该Email附件的一张图片。
这时候EmailActivity和PictrueActivity就是在同一个任务中的。
突然间,我们因为其它原历,需要按下Home键回到Launcher中去完成其它任务。
完成其它任务之后,再点击Launcher上面的EmailActivity图标来想重新浏览之前正在查看的Email,但是又不想看到的是该Email附件的那张图片。
在这种情况下,之前在启动PictrueActivity来查看Email的附件图片时,就可以将用来启动PictrueActivity的一个Intent对象的标志值的Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET位设置为1。
无论如何,最终指定的切换动画的类型都是通过调用ActivityStack类的成员变量mService所指向的一个ActivityManagerService对象的成员变量mWindowManager所描述的一个WindowManagerService对象的成员函数prepareAppTransition来通知WindowManagerService服务的。
ActivityStack类的成员函数startActivityLocked通知WindowManagerService服务准备好一个Activity组件切换操作之后,如果参数doResume的值等于true,那么它就会继续调用另外一个成员函数resumeTopActivityLocked来继续执行启动参数r所描述的一个Activity组件的操作。
接下来,我们就首先分析WindowManagerService类的成员函数prepareAppTransition的实现,以便可以了解WindowManagerService服务是如何准备一个Activity组件切换操作的,然后再回过头来分析ActivityStack类的成员函数resumeTopActivityLocked是如何继续执行启动参数r所描述的一个Activity组件的操作的。
Step2.WindowManagerService.prepareAppTransition
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
publicclassWindowManagerServiceextendsIWindowManager.Stub
implementsWatchdog.Monitor{
......
//Statemanagementofapptransitions.Whenwearepreparingfora
//transition,mNextAppTransitionwillbethekindoftransitionto
//performorTRANSIT_NONEifwearenotwaiting.Ifwearewaiting,
//mOpeningAppsandmClosingAppsarethelistsoftokensthatwillbe
//madevisibleorhiddenatthenexttransition.
intmNextAppTransition=WindowManagerPolicy.TRANSIT_UNSET;
......
booleanmAppTransitionReady=false;
......
booleanmAppTransitionTimeout=false;
booleanmStartingIconInTransition=false;
booleanmSkipAppTransitionAnimation=false;
publicvoidprepareAppTransition(inttransit){
if(!
checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"prepareAppTransition()")){
thrownewSecurityException("RequiresMANAGE_APP_TOKENSpermission");
}
synchronized(mWindowMap){
......
if(!
mDisplayFrozen&&mPolicy.isScreenOn()){
if(mNextAppTransition==WindowManagerPolicy.TRANSIT_UNSET
||mNextAppTransition==WindowManagerPolicy.TRANSIT_NONE){
mNextAppTransition=transit;
}elseif(transit==WindowManagerPolicy.TRANSIT_TASK_OPEN
&&mNextAppTransition==WindowManagerPolicy.TRANSIT_TASK_CLOSE){
//Openinganewtaskalwayssupersedesaclosefortheanim.
mNextAppTransition=transit;
}elseif(transit==WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
&&mNextAppTransition==WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE){
//Openinganewactivityalwayssupersedesaclosefortheanim.
mNextAppTransition=transit;
}
mAppTransitionReady=false;
mAppTransitionTimeout=false;
mStartingIconInTransition=false;
mSkipAppTransitionAnimation=false;
mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
mH.sendMessageDelayed(mH.obtainMessage(H.APP_TRANSITION_TIMEOUT),
5000);
}
}
}
......
}
这个函数定义在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
调用WindowManagerService类的成员函数prepareAppTransition来通知WindowManagerService服务准备一个Activity组件切换操作是需要具有android.Manifest.permission.MANAGE_APP_TOKENS,否则的话,WindowManagerService类的成员函数prepareAppTransition就会抛出一个类型为SecurityException的异常。
WindowManagerService类的成员变量mNextAppTransition描述的就是WindowManagerService服务接下来要执行一个Activity组件切换操作的类型,也就是要执行的一个Activity组件切换动画的类型。
WindowManagerService类的成员函数prepareAppTransition按照以下规则来设置WindowManagerService服务接下来要执行的Activity组件切换动画的类型:
1.当WindowManagerService类的成员变量mNextAppTransition的值等于WindowManagerPolicy.TRANSIT_UNSET或者WindowManagerPolicy.TRANSIT_NONE的时候,就说明WindowManagerService服务接下来没有Activity组件切换动画等待执行的,这时候参数transit所描述的Activity组件切换动画就可以作为WindowManagerService服务接下来要执行的Activity组件切换动画。
2.当WindowManagerService类的成员变量mNextAppTransition的值等于WindowManagerPolicy.TRANSIT_TASK_CLOSE,那么就说明WindowManagerService服务接下来要执行一个关闭Activity组件任务的切换动画等待执行的。
在这种情况下,如果参数transit所描述的是一个打开Activity组件任务的切换动画,即它的值等于WindowManagerPolicy.TRANSIT_TASK_OPEN,那么就需要将WindowManagerService服务接下来要执行的Activity组件切换动画为打开Activity组件任务类型的。
这是因为打开Activity组件任务的切换动画的优先级高于关闭Activity组件任务的切换动画。
3.当WindowManagerService类的成员变量mNextAppTransition的值等于WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE,那么就说明WindowManagerService服务接下来要执行一个关闭Activity组件的切换动画等待执行的。
在这种情况下,如果参数transit所描述的是一个打开Activity组件的切换动画,即它的值等于WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN,那么就需要将WindowManagerService服务接下来要执行的Activity组件切换动画为打开Activity组件类型的。
这是因为打开Activity组件的切换动画的优先级高于关闭Activity组件的切换动画。
设置好WindowManagerService服务接下来要执行的Activity组件切换动画的类型之后,WindowManagerService类的成员函数prepareAppTransition还会将其余四个成员变量mAppTransitionReady、mAppTransitionTimeout、mStartingIconInTransition和mSkipAppTransitionAnimation的值设置为false,其中:
1.mAppTransitionReady表示WindowManagerService服务可以开始执行一个Activity组件的切换动画了没有?
2.mAppTransitionTimeout表示WindowManagerService服务正在执行的Activity组件切换动画是否已经超时?
3.mStartingIconInTransition表示WindowManagerService服务开始显示正在启动的Activity组件的启动窗口了没有?
4.mSkipAppTransitionAnimation表示WindowManagerService服务是否需要不执行Activity组件的切换动画?
最后,WindowManagerService类的成员函数prepareAppTransition还会调用成员变量mH所描述的一个H对象的成员函数sendMessageDelayed来向WindowManagerService服务所运行在的线程发送一个类型为APP_TRANSITION_TIMEOUT的消息。
这个消息将在5秒后被执行,是用来强制前面所设置的Activity组件切换动画要在5秒之内执行完成的,否则的话,WindowManagerService服务就会认为该切换动画执行超时了。
这一步执行完成之后,WindowManagerService服务接下来要执行的Activity组件切换操作或者说切换动画就准备完成了。
注意,这时候只是准备好Activity组件切换动画,但是这个切换动画还不能执行,要等到前一个激活的Activity组件进入到Paused状态并且接下来正在启动的Activity组件进入到Resumed状态之后才能执行。
回到前面的Step1中,即ActivityStack类的成员函数startActivityLocked,接下来它就会调用另外一个成员函数resumeTopActivityLocked来继续启动指定的Activit
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Android窗口管理服务WindowManagerService切换Activity窗口App Transition的过程分析 Android 窗口 管理 服
链接地址:https://www.bdocx.com/doc/27752621.html