Android窗口管理服务WindowManagerService切换Activity窗口(App Transition)过程分析.doc_第1页
Android窗口管理服务WindowManagerService切换Activity窗口(App Transition)过程分析.doc_第2页
Android窗口管理服务WindowManagerService切换Activity窗口(App Transition)过程分析.doc_第3页
Android窗口管理服务WindowManagerService切换Activity窗口(App Transition)过程分析.doc_第4页
Android窗口管理服务WindowManagerService切换Activity窗口(App Transition)过程分析.doc_第5页
已阅读5页,还剩31页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Android窗口管理服务WindowManagerService切换Activity窗口(App Transition)的过程分析在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个步骤,接下来我们就详细分析每一个步骤。 Step 1. ActivityStack.startActivityLockedjava view plain copy 在CODE上查看代码片派生到我的代码片public class ActivityStack . private final void startActivityLocked(ActivityRecord r, boolean newTask, boolean doResume) final int NH = mHistory.size(); int addPos = -1; if (!newTask) / If starting in an existing task, find where that is. . / Place a new activity at top of stack, so it is next to interact / with the user. if (addPos 0) . if (ent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) mService.mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE); . else if (ent.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组件可以显示出来。例如,如果我们正在使用一个Email Activity组件来查看Email,这时候又需要启动另外一个Pictrue Activity来查看该Email附件的一张图片。这时候Email Activity与Pictrue Activity就是在同一个任务中的。突然间,我们因为其它原历,需要按下Home键回到Launcher中去完成其它任务。完成其它任务之后,再点击Launcher上面的Email Activity图标来想重新浏览之前正在查看的Email,但是又不想看到的是该Email附件的那张图片。在这种情况下,之前在启动Pictrue Activity来查看Email的附件图片时,就可以将用来启动Pictrue Activity的一个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组件的操作的。 Step 2. WindowManagerService.prepareAppTransitionjava view plain copy 在CODE上查看代码片派生到我的代码片public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor . / State management of app transitions. When we are preparing for a / transition, mNextAppTransition will be the kind of transition to / perform or TRANSIT_NONE if we are not waiting. If we are waiting, / mOpeningApps and mClosingApps are the lists of tokens that will be / made visible or hidden at the next transition. int mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET; . boolean mAppTransitionReady = false; . boolean mAppTransitionTimeout = false; boolean mStartingIconInTransition = false; boolean mSkipAppTransitionAnimation = false; public void prepareAppTransition(int transit) if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, prepareAppTransition() throw new SecurityException(Requires MANAGE_APP_TOKENS permission); synchronized(mWindowMap) . if (!mDisplayFrozen & mPolicy.isScreenOn() if (mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET | mNextAppTransition = WindowManagerPolicy.TRANSIT_NONE) mNextAppTransition = transit; else if (transit = WindowManagerPolicy.TRANSIT_TASK_OPEN & mNextAppTransition = WindowManagerPolicy.TRANSIT_TASK_CLOSE) / Opening a new task always supersedes a close for the anim. mNextAppTransition = transit; else if (transit = WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN & mNextAppTransition = WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE) / Opening a new activity always supersedes a close for the anim. 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状态之后才能执行。 回到前面的Step 1中,即ActivityStack类的成员函数startActivityLocked,接下来它就会调用另外一个成员函数resumeTopActivityLocked来继续启动指定的Activity组件。从前面一文可以知道,ActivityStack类的成员函数resumeTopActivityLocked以及接下来要调用的其它成员函数就是执行以下两个操作: 1. 通知当前处于激活状态的Activity组件所运行在的应用程序进程,它所运行的一个Activity组件要由Resumed状态进入到Paused状态了。 2. 检查用来运行当前正在启动的Activity组件的应用程序进程是否已经启动起来了。如果已经启动起来,那么就会直接通知该应用程序进程将正在启动的Activity组件加载起来,否则的话,就会先将该应用程序进程启动起来,然后再通知它将正在启动的Activity组件加载起来。 在第2步中,通知相应的应用程序进程将正在启动的Activity组件加载起来是通过调用ActivityStack类的成员函数realStartActivityLocked来实现的,接下来我们就继续分析这个成员函数的实现,以便可以继续了解Activity组件的切换操作的执行过程。 Step 3. ActivityStack.realStartActivityLockedjava view plain copy 在CODE上查看代码片派生到我的代码片public class ActivityStack . final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app, boolean andResume, boolean checkConfig) throws RemoteException . mService.mWindowManager.setAppVisibility(r, true); . try . app.thread.scheduleLaunchActivity(new Intent(ent), r, System.identityHashCode(r), , r.icicle, results, newIntents, !andResume, mService.isNextTransitionForward(); . catch (RemoteException e) . . if (andResume) / As part of the process of launching, ActivityThread also performs / a resume. r.state = ActivityState.RESUMED; . mResumedActivity = r; . completeResumeLocked(r); . . return true; . 这个函数定义在文件frameworks/base/services/java/com/android/server/am/ActivityStack.java中。 ActivityStack类的成员函数realStartActivityLocked主要执行以下三个操作: 1. 通知WindowManagerService服务将参数r所描述的Activity组件的可见性设置为true,这是通过调用ActivityStack类的成员变量mService所指向的一个ActivityManagerService对象的成员变量mWindowManager所描述的一个WindowManagerService对象的成员函数setAppVisibility来实现的。 2. 通知参数r所描述的Activity组件所运行在的应用程序进程将它加载起来,这是通过调用参数app所指向的一个ProcessRecord对象的成员变量thread所描述的一个类型为ApplictionThread的Binder代理对象的成员函数scheduleLaunchActivity来实现的。 3. 当参数andResume的值等于true的时候,就表示在执行第2步时,参数r所描述的Activity组件所运行在的应用程序进程已经将它的状态设置为Resumed了,即已经调用过它的成员函数onResume了。在这种情况,ActivityManagerService服务也需要将该Activity组件的状态设置为Resumed了,即将r所指向的一个ActivityRecord对象的成员变量state的值设置为ActivityState.RESUMED,并且将ActivityStack类的成员变量mResumedActivity的值设置为r,以便表示当前激活的Activity组件为参数r所描述的Activity组件。最后,ActivityManagerService服务还需要调用ActivityStack类的成员函数completeResumeLocked来通知WindowManagerService服务执行在前面Step 2所准备好的Activity组件切换操作。 接下来,我们首先分析WindowManagerService类的成员函数setAppVisibility的实现,以便可以了解WindowManagerService服务是如何设置一个Activity组件的可见性的,接着再分析ActivityStack类的成员函数completeResumeLocked的实现,以便可以了解ActivityManagerService服务是如何通知WindowManagerService服务执行前面所准备好的一个Activity组件切换操作的。 Step 4. WindowManagerService.setAppVisibilityjava view plain copy 在CODE上查看代码片派生到我的代码片public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor . public void setAppVisibility(IBinder token, boolean visible) if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, setAppVisibility() throw new SecurityException(Requires MANAGE_APP_TOKENS permission); AppWindowToken wtoken; synchronized(mWindowMap) wtoken = findAppWindowToken(token); . / If we are preparing an app transition, then delay changing / the visibility of this token until we execute that transition. if (!mDisplayFrozen & mPolicy.isScreenOn() & mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) / Already in requested state, dont do anything more. if (wtoken.hiddenRequested != visible) return; wtoken.hiddenRequested = !visible; . wtoken.setDummyAnimation(); mOpeningApps.remove(wtoken); mClosingApps.remove(wtoken); wtoken.waitingToShow = wtoken.waitingToHide = false; wtoken.inPendingTransaction = true; if (visible) mOpeningApps.add(wtoken); wtoken.startingDisplayed = false; wtoken.startingMoved = false; / If the token is currently hidden (should be the / common case), then we need to set up to wait for / its windows to be ready. if (wtoken.hidden) wtoken.allDrawn = false; wtoken.waitingToShow = true; if (wtoken.clientHidden) / In the case where we are making an app visible / but holding off for a transition, we still need / to tell the client to make its windows visible so / they get drawn. Otherwise, we will wait on / performing the transition until all windows have / been drawn, they never will be, and we are sad. wtoken.clientHidden = false; wtoken.sendAppVisibilityToClients(); else mClosingApps.add(wtoken); / If the token is currently visible (should be the / common case), then set up to wait for it to be hidden. if (!wtoken.hidden) wtoken.waitingToHide = true; return; . setTokenVisibilityLocked(wtoken, null, visible, WindowManagerPolicy.TRANSIT_UNSET, true); wtoken.updateReportedVisibilityLocked(); . . 这个函数定义在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。 调用WindowManagerService类的成员函数setAppVisibility来设置Activity组件的可见性需要具有android.Manifest.permission.MANAGE_APP_TOKENS权限,否则的话,WindowManagerService类的成员函数setAppVisibility就会抛出一个类型为SecurityException的异常。 从前面一文可以知道,每一个Activity组件在WindowManagerService服务内部都对应有一个AppWindowToken对象,用来描述该Activity组件的窗口在WindowManagerService服务中的状态。因此,WindowManagerService类的成员函数setAppVisibility就先通过调用成员函数findAppWindowToken来找到与参数token所描述的一个Activity组件所对应的一个AppWindowToken对象wtoken,以便接下来可以设置它的状态。 注意,WindowManagerService类的成员函数setAppVisibility在修改参数token所描述的一个Activity组件的

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论