网站建设捌金手指下拉七html5网站制作分工

当前位置: 首页 > news >正文

网站建设捌金手指下拉七,html5网站制作分工,soso网站提交入口,网站怎么做网站收录ActivityManagerService#xff08;AMS#xff09;是Android提供的一个用于管理Activity#xff08;和其他组件#xff09;运行状态的系统进程 AMS功能概述 和WMS一样#xff0c;AMS也是寄存于systemServer中的。它会在系统启动时#xff0c;创建一个线程来循环处理客户…ActivityManagerServiceAMS是Android提供的一个用于管理Activity和其他组件运行状态的系统进程 AMS功能概述 和WMS一样AMS也是寄存于systemServer中的。它会在系统启动时创建一个线程来循环处理客户的请求。值得一提的是AMS会向ServiceManager登记多种Binder Server如“activity” “meminfo” “cpuinfo”等——不过只有第一个“activity”才是AMS的“主业”并由Activity ManagerService实现剩余服务的功能则是由其他类提供的 先来看看AMS的启动过程。如下所示 /frameworks/base/services/java/com/android/server/SystemServer .java/ public void run() {…Slog.i(TAG, Activity Manager);context ActivityManagerService.main(factoryTest); //启动AMS…ActivityManagerService.setSystemProcess(); //向ServiceManager注册… }ActivityManagerService提供了一个静态的main函数通过它可以轻松地启动AMS。然后还需要调用setSystemProcess来把这个重要系统服务注册到ServiceManager。由此可见它和WMS一样都是“实名” 的Binder Server /frameworks/base/services/java/com/android/server/am/ActivityM anagerService.java/public static final Context main(int factoryTest) {AThread thr new AThread(); //创建AMS线程thr.start(); //启动AMS线程synchronized (thr) {while (thr.mService null) {/*注意这段代码是运行在SystemServer所在线程中的。所以通过mService是否为空来判断AMS成功启动与否如果是的话就可以返回SystemServer 继续执行否则就一直等待。Android在处理“系统级进程”出错时的普遍态度是“既然系统都出错 了任何补救都是无力回天的”所以它的异常处理部分经常是空的 */try {thr.wait();} catch (InterruptedException e) {}}}…m.mMainStack new ActivityStack(m, context, true); /创建一个ActivityStack对象 这是AMS的核心很多工作都是围绕它展开的/… return context;}对于SystemServer所在线程来说它需要等到AThread即上述的变量thr成功启动后才能继续往下执行。所以当thr.start()后就通过thr.wait()进入等待。那么什么时候唤醒呢答案就在AThread内部 public void run() {…synchronized (this) {mService m;mLooper Looper.myLooper();notifyAll();}上面的notifyAll会唤醒所有在thr这个object所在等待队列上的目标自然也就包括了SystemServer所属线程。这么做的原因是SystemServer的后续运行将依赖于AMS所以如果在AMS还未就绪的情况下就贸然返回很可能会造成系统宕机。 将AMS注册到ServiceManager很简单唯一要注意的是它不只注册了自己一个Server而是一系列与进程管理相关的服务。如下所示 public static void setSystemProcess() {try {ActivityManagerService m mSelf; ServiceManager.addService(activity, m, true);//AMS的主业ServiceManager.addService(meminfo, new MemBinder(m));//内存使用情况…//其他服务省略}管理当前系统中Activity状态——ActivityStack 以下内容是从ActivityStack.java中提取出来的。 1ActivityState 描述了一个Activity所可能经历的所有状态。其定义如下 INITIALIZING, //正在初始化 RESUMED, //恢复 PAUSING, //正在暂停 PAUSED, //已经暂停 STOPPING, //正在停止 STOPPED, //已经停止 FINISHING, //正在完成 DESTROYING, //正在销毁 DESTROYED //已经销毁 }2.ArrayList 除了状态管理外ActivityStack中还有一系列不同功能的ArrayList成员变量。它们的共同点在于列表元素都是ActivityRecord——这个类负责记录每个Activity的运行时信息。因而也可以看出ActivityStack确实是AMS中管理Activity的“大仓库”。 3.记录特殊状态下的Activity 除了上面的ArrayList用来描述各种状态下的Activity集合外ActivityStack还通过以下多个变量来专门记录一些特殊状态下的Activity实例具体如表8-2所示。 以上所述的3类变量构成了ActivityStack的主框架。如果用一句话来简单概述AMS的功能就是 “AMS是通过ActivityStack和其他数据结构来记录、管理系统中的Activity和其他组件状态并提供查询功能的一个系统服务。”这句话包含了以下几个重点。1AMS的主要工作就是管理、记录、查询 打个比方AMS就像户籍登记处。所有新加入或者注销的家庭都需要到这里办理业务而且它还提供对外的查询功能——这点类似于公安局开具的“户籍证明”用于表明办证者当前的户口状态。2AMS是系统进程的一部分确切地说它运行于一个独立的线程中 从内核的角度来说AMS其实也是普通进程中的一部分只不过它提供的是全局性的系统服务。接着上面打的比方户籍登记处和家庭一样也是在一个“房子”进程里运行的。它有一套严格的办事规程线程来处理户主的各种请求登记、注销、查询等。值得一提的是AMS的任务只是负责保管Activity及其他组件的状态信息而像Activity中描述的UI界面如何在物理屏幕上显示等工作则是由WindowManagerService和SurfaceFlinger来完成的 startActivity流程 相信大家对startActivity(Intent)的功能不会陌生。它用于启动一个目标Activity——具体是哪个Activity则是AMS通过对系统中安装的所有程序包进行“Intent匹配”得到的并不局限于调用者本身所在的package范围。换句话说startActivity()最终很可能启动的是其他进程中的组件。当系统匹配到某个目标Activity后分为两种情况。 如果通过Intent匹配到的目标对象其所属程序包中已经有其他元 素在运行意味着该程序进程已启动那么AMS就会通知这个 进程来加载运行我们指定的目标Activity。如果当前Activity所属程序没有进程在运行AMS就会先启动它的一个实例然后让其运行目Activity。 先大致讲解一下startActivity()所经历的函数调用流程从调用方Activity1开始Activity1→ startActivityContextImpl.java→execStartActivityInstrumentation.java→startActivityActivityManager Service.java。 因而经过层层中转后调用者发起的startActivity最终还是在AMS中实现的。接下来的问题就转化为AMS内部对startActivity是如何处理的 看似简单的一个功能实际上AMS要做的工作还是很多的——首先来辨别下AMS中5个“长相”类似的 startActivity函数以防后期混淆。统一列出如下 startActivityActivityManagerService.java startActivityAsUser ActivityManagerService.java startActivityMayWaitActivityStack.java startActivityLockedActivityStack.java startActivityUncheckedLockedActivityStack.java这5个函数存在先后调用的关系。源代码如下 /frameworks/base/services/java/com/android/server/am/ActivityMa nagerService.java/public final int startActivity(IApplicationThread caller, String callingPackage,Intent intent, String resolvedType, IBinder resultTo,String resultWho, int requestCode, int startFlags,String profileFile, ParcelFileDescriptor profileFd, Bundle options) {return startActivityAsUser(caller, callingPackage, intent, resolvedType,result To, resultWho, requestCode, startFlags, profileFile, profileFd, options,UserHandle.getCallingUserId());}可以看到startActivityAsUser与startActivity只多了最后一个参数userId它表示调用者的用户ID值因而可以通过Binder机制的getCallingUid获得 public final int startActivityAsUser(IApplicationThread caller, String calling Package,Intent intent, String resolvedType, IBinder resultTo,String resultWho, int requestCode, int startFlags, String profileFile,ParcelFileDescriptor profileFd, Bundle options, int userId {enforceNotIsolatedCaller(startActivity);userId handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,false, true, startActivity, null);return mMainStack.startActivityMayWait(caller,-1,callingPackage,intent, resolvedType,resultTo, resultWho, requestCode, startFlags, profileFile, profileFd,null, null, options, userId);/这个函数是ActivityStack提供的/}函数startActivityAsUser的一大重点就是做权限检查包括 enforceNotIsolatedCaller 检查调用者是否属于被隔离的对象。handleIncomingUser 调用者是否有权力执行这一操作 5个“startActivityXX”其实是5个执行步骤而且一旦其中一步出现错误就会中止整个流程。接着往下分析startActivityMayWait这个函数。因为代码很长我们直接把其中的核心工作提取出来如图8-2所示。 根据图8-2中的描述在startActivityMayWait中要启动某个符合Intent要求的Activity那么首先就应确定这个目标Activity如果是显式的Intent问题很好解决因为Intent信息中已经带有目标Activity的相关信息否则就调用resolveActivity()进行查找判断目标Activity所属进程是不是重量级heavy-weight的。如果当前系统中已经存在的重量级进程mService.mHeavyWeightProcess不是即将要启动的这个那么就要给Intent重新赋值。调用startActivityLocked来进一步执行启动工作。如果outResult不为空还需要将函数的结果写入这个变量中。 这个函数的名称表明它有可能会“wait”——具体就表现在对outResult的处理上。 AMS中startActivity的过程如图8-5所示。
完成同一任务的“集合”——Activity Task Android系统中应用程序的一大特色就是它们不仅可以“装载”众多系统组件而且可以把这些组件跨进程地组成ActivityTask。这个特性使得每个应用都不是孤立的从而能最大限度地实现资源复用。举个例子一个短信应用程序至少会有“已收短信列表”、“阅读短信”和“编辑短信”3个子功能——在Android体系中它们分别对应3个Activity。 从程序包Package的组织角度来说这3个元素只属于“短信”这个程序。但事实上Activity的设计意图已经超越了单一的进程概念。换句话说这几个Activity不仅在“短信”这一程序可以非常方便地互相调用比如用户在“已收短信列表”中点击任何一条短信就可以进入“短信阅读”其他需要使用“短信”功能的进程也能通过startActivity(Intent)来复用它们。比如我们在浏览电话本时可以将某个人的联系方式通过短信发送出去。电话本程序并不需要专门实现短信的编辑和发送只需填写这一请求Intent然后利用startActivity(Intent)告诉系统余下的事情就会有相应的“志愿者”去帮它完成。 在这一过程中系统先后启动了“联系人详情”和“短信编辑”两个不同进程中的Activity来共同完成“通过短信发送联系人信息”的任务这就是ActivityTask概念的直观体现。从数据结构的角度来讲Task有先后之分所以源码实现上采用了Stack栈的方式。在本例中“联系人详情”这个Activity是首先启动并被压栈的随后“栈顶”的位置被“短信编辑”所取代——直到短信发送完成后被销毁此时就又会“显示”出原来的那个“联系人详情”的Activity了。 ActivityTask机制打破了应用程序的常规使用界限从而增强了用户体验。同时也给程序的管理和实现增加了一定难度。上面已经说过Task运用的是“栈”管理方式那么在AMS中具体是如何实现的呢当前系统应该不仅有一个Task而是众多Task的集合这些Task间又有什么联系用户是否可以控制和调整这些Task间的联系呢 回答是肯定的。Android系统提供了一系列Flag标志来允许用户对Task进行实时调整正确理解和使用这些flag无疑会让应用程序更贴近用户的使用习惯。 1.1 “后进先出”——Last InFirst Out 传统意义上“栈”的思想就是“Last In, First Out”。通俗地讲就是“后进先出”——先入栈的元素会被压在栈底而后续元素不断往上堆栈。因而出栈时自然是最后的那个元素在先然后才是下面的元素直到栈底。 从上述“栈”的概念来衡量ActivityTask并不能算是严格意义的Stack——它在默认情况下和栈是一致的但比栈提供了更多的操作方式因而可以理解为“栈的一种变异”。 1.2 管理Activity Task 前一小节所述的Activity Task已经能满足开发者的一般需求但是在某些情况下我们还希望拥有更多的灵活性。比如在启动一个新的Activity时我们可能不希望它和当前的Activity处于同一个Task中或者我们希望当新的Activity运行时系统可以先清空当前的Task等。Android系统提供了丰富的接口方法来满足程序员的类似需求 应用程序可以通过两种方法来影响Activity Task的默认行为。 方法1在 activity标签中指定属性 android:taskAffinity Affinity即“喜好倾向”它代表这个Activity所希望归属的Task。在默认情况下同一个应用程序中的所有Activity拥有共同的Affinity即AndroidManifest.xml中声明的Package Name。当然也可以主动在 application中使用taskAffinity标签属性来指定整个应用程序的Affinity。 一个Activity Task的Affinity属性取决于它的根Activity。 那么taskAffinity在什么情况下产生效果 1当启动Activity的Intent中带有FLAG_ACTIVITY_NEW_TASK标志时 在默认情况下目标Activity将与startActivity的调用者处于同一Task中。但如果用户特别指定了FLAG_ACTIVITY_NEW_TASK表明它希望为Activity重新开设一个Task。这时就有两种情况假如当前已经有一个Task它的affinity与新Activity是一样的那么系统会直接用此Task来完成操作而不是另外创建一个Task否则系统需要重启一个Task。 2当Activity中的allowTaskReparenting属性设置为true时。在这种情况下Activity具有“动态转移”的能力。举个前面的“短信”例子在默认情况下该应用程序中的所有Activity具有相同的affinity。当另一个程序启动了“短信编辑”时一开始这个Activity和启动它的Activity处于同样的Task中。但如果“短信编辑”Activity指定了allowTaskReparenting且后期“短信”程序的Task转为前台此时“短信编辑”这一Activity会被“挪”到与它更亲近的“短信”Task中。 android:launchMode 用于指定Activity被启动的方式。主要包括两方面的内容即Activity是否为单实例以及Activity归属的Task。不论是何种方式最终被启动的Activity通常情况下都要位于ActivityTask的栈顶因为只有在栈顶的Activity才是可以直接与用户交互的。一共有4种launchMode如表8-3所示。 关于启动模式看一下官网的介绍 android:launchMode 有关应如何启动 activity 的指令。共有五种模式可与 Intent 对象中的 activity 标记FLAGACTIVITY* 常量协同工作以确定在调用 activity 处理 intent 时应执行的操作。它们是 “standard” “singleTop” “singleTask” “singleInstance” “singleInstancePerTask” 默认模式为“standard”。 如下表所示这些模式可分为两大类“standard”和“singleTop”activity 为一类“singleTask”“singleInstance”和“singleInstancePerTask”activity 为另一类。启动模式为“standard”或“singleTop”的 activity 可以多次实例化。实例可归属任何任务并且可位于 activity 任务中的任何位置。通常它们会启动到名为 startActivity() 的任务中除非 intent 对象包含 FLAG_ACTIVITY_NEW_TASK 指令在此情况下会选择其他任务 - 请参阅 taskAffinity 属性。 相比之下“singleTask” “singleInstance” 和 “singleInstancePerTask” activity 的行为有所不同。“singleInstancePerTask”始终位于 activity 任务的根位置。此外设备一次只能保留一个 “singleInstance” activity 实例而 “singleInstancePerTask” activity 在 FLAG_ACTIVITY_MULTIPLE_TASK 或 FLAG_ACTIVITY_NEW_DOCUMENT 已设置的情况下在不同的任务中可以多次实例化。启动模式为 “singleTask” 的 activity 结合了 “singleInstance” 和 “singleInstancePerTask” 的行为activity 可以多次实例化并且可以位于具有相同 taskAffinity 的任务中的任意位置。同时设备只能保留一个用于在 activity 任务的根位置查找 “singleTask” activity 的任务。 “standard”和“singleTop”模式只有一个不同之处每次“standard”activity 有一个新的 intent 时系统都会创建类的新实例来响应该 intent。每个实例处理单个 Intent。同样地您也可以创建新的“singleTop”activity 实例来处理新的 intent。不过如果目标任务的 activity 堆栈顶部已有一个 activity 实例则该实例会通过调用 onNewIntent()接收新的 intent此时不会创建新实例。在其他情况下例如如果“singleTop”activity 的某个现有实例虽在目标任务内但未处于堆栈顶部或者虽然位于堆栈顶部但不在目标任务中系统会创建新实例并将其送入堆栈。 同样地如果您向上导航到当前堆栈上的某个 activity则该行为由父 activity 的启动模式决定。如果父 activity 有启动模式 singleTop或者 up intent 包含 FLAG_ACTIVITY_CLEAR_TOP则系统会将该父项置于堆栈顶部并保留其状态。导航 Intent 由父 Activity 的 onNewIntent() 方法接收。如果父 activity 有启动模式 standard并且 up intent 不包含 FLAG_ACTIVITY_CLEAR_TOP则系统会将当前 activity 及其父项同时送出堆栈并创建新的父 activity 实例来接收导航 intent。 “singleInstance”模式也与“singleTask”和“singleInstancePerTask”有一个不同之处具有“singleTask”或“singleInstancePerTask”启动模式的 activity 允许其他 activity必须是“standard”和“singleTop”activity成为其任务的一部分。另一方面“singleInstance”activity 不允许任何其他 activity 成为其任务的一部分它必须是任务中唯一的 activity。如果它启动另一个 activity则系统会将该 activity 分配给其他任务就如同 intent 中包含 FLAG_ACTIVITY_NEW_TASK 一样。 如上表所示standard 是默认模式适用于大多数类型的 activity。对众多类型的 activity 而言SingleTop 也是常见且有用的启动模式。其他模式singleTask、singleInstance 和 singleInstancePerTask不适用于大多数应用因为它们所形成的交互模式可能让用户感到陌生并且与大多数其他应用差别较大。 关于启动模式进行一些补充来源于《Android开发艺术探索》 ( 1) standard:标准模式这也是系统的默认模式。每次启动一个Activity都会重新创建一个新的实例不管这个实例是否已经存在。被创建的实例的生命周期符合典型情况下Activity 的生命周期它的 onCreate、onStart、onResume都会被调用。这是一种典型的多实例实现一个任务栈中可以有多个实例每个实例也可以属于不同的任务栈。在这种模式下,谁启动了这个 Activity,那么这个 Activity就运行在启动它的那个Activity所在的栈中。比如 Activity A启动了Activity B(B是标准模式)那么B就会进入到A所在的栈中。不知道读者是否注意到当我们用ApplicationContext去启动standard模式的Activity的时候会报错错误如下: 相信这句话读者一定不陌生这是因为 standard模式的Activity 默认会进入启动它的Activity所属的任务栈中但是由于非Activity类型的Context如 ApplicationContext并没有所谓的任务栈所以这就有问题了。解决这个向题的方法是为待启动Activity指定FLAG_ACTIVITY_NEW_TASK标记位这样启动的时候就会为它创建一个新的任务栈这个时候待启动Activity实际上是以 singleTask模式启动的。 (2) singleTop:栈顶复用模式。在这种模式下如果新Activity已经位于任务栈的栈顶那么此Activity不会被重新创建同时它的onNewIntent方法会被回调通过此方法的参数我们可以取出当前请求的信息。需要注意的造这个Activity 的 onCreate、onStart不会被系统调用因为它并没有发生改变。如果新Activity 的实例已存在但不是位于栈顶那么新Activity仍然会重新重建。举个例子假设目前栈内的情况为ABCD其中 ABCD为四个 ActivityA位于栈底D位于栈顶这个时候假设要再次启动D如果D的启动模式为singleTop那么栈内的情况仍然为ABCD;如果D的启动模式为standard那么由于D被重新创建导致栈内的情况就变为ABCDD。 (3 ) singleTask:栈内复用模式。这是一种单实例模式在这种模式下只要 Activity在一个栈中存在那么多次启动此Activity都不会重新创建实例和 singleTop一样系统也会回调其 onNewIntent。具体一点当一个具有singleTask模式的Activity请求启动后比如Activity A系统首先会寻找是否存在A想要的任务栈如果不存在就重新创建一个任务栈然后创建A的实例后把A放到栈中。如果存在A所需的任务栈这时要看A是否在栈中有实例存在如果有实例存在那么系统就会把A调到栈顶并调用它的 onNewIntent方法如果实例不存在就创建A的实例并把A压入栈中。举几个例子: 比如目前任务栈S1中的情况为ABC这个时候Activity D以singleTask模式请求启动其所需要的任务栈为S2由于S2和D的实例均不存在所以系统会先创建任务栈S2然后再创建D的实例并将其入栈到S2。另外一种情况假设D所需的任务栈为S1其他情况如上面例子1所示那么由于S1已经存在所以系统会直接创建D的实例并将其入栈到S1。如果D所需的任务栈为S1并且当前任务栈S1的情况为ADBC根据栈内复用的原则此时D不会重新创建系统会把D切换到栈顶并调用其 onNewIntent方法同时由于singleTask默认具有clearTop的效果,会导致栈内所有在D上面的Activity全部出栈于是最终S1中的情况为AD。 ( 4)singleInstance:单实例模式。这是一种加强的singleTask模式,它除了具有singleTask模式的所有特性外还加强了一点那就是具有此种模式的Activity只能单独地位于一个任务栈中换句话说比如Activity A是singleInstance模式当A启动后系统会为它创建一个新的任务栈然后A独自在这个新的任务栈中由于栈内复用的特性后续的请求均不会创建新的Activity除非这个独特的任务栈被系统销毁了。 android:clearTaskOnLaunch 清除Task中所有除root activity的元素。可想而知这个属性只对root activity设置有效task中其他activity设置此属性是无效的。android:alwaysRetainTaskState 如果用户在一定时间内不再访问Task比如说30分钟那么系统就有可能会清除task中的状态只保留root activity。设置此属性为“true”可以避免这种情况。android:finishOnTaskLaunch 当Task被再次启动时activity是否需要销毁。这个属性比allowTaskReparenting优先级高。也就是说这种情况下activity不 会被重新指定task而是直接销毁。 方法2使用Intent标志 除了在标签中声明task属性外我们也可以在启动一个Activity(startActivity)时通过Intent来动态指定所需的task属性值。Activity中静态标注的属性和后面startActivity所指定的Intent有冲突则以Intent为准。 FLAG_ACTIVITY_NEW_TASK 这个和前面的singleTask启动模式的作用是一样的。FLAG_ACTIVITY_SINGLE_TOP 这个和前面的singleTop启动模式的作用是一样的。FLAG_ACTIVITY_CLEAR_TOP 和上面两个不同launchMode中没有与此对应的模式。它所代表的含义是如果要启动的Activity已经在当前task中运行那么所有在它之上的Activity都将被销毁并且Intent通过onNewIntent传给它这时它会被resumed。 另外还有几个Intent标志对我们分析AMS有帮助一并列出如下。 FLAG_ACTIVITY_NO_HISTORY 这个Activity将不会被保存在History Stack中。同样的效果也可以通过在AndroidManifest.xml中添加“android:noHistory”来实现。FLAG_ACTIVITY_MULTIPLE_TASK 这个标志需要和FLAG_ACTIVITY_NEW_TASK一同使用否则没有效果。它将阻止系统恢复一个现有的task比如我们要启动的Activity已经在这个Task中。换句话说系统总是启动一个新的task来容纳要启动的Activity。FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 如果设置了这个标志则Activity不会被放在系统“最近启动的Activity列表”中。FLAG_ACTIVITY_BROUGHT_TO_FRONT 在launchMode中使用了singleTask后系统会自动加上这个标志。FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 使用此标志当Activity在新task中启动或者在已有task中启动都会处于task的上端。FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY 系统自动设置的说明这个Activity是从历史记录中启动的长按HOME键可以调出。FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET 一般情况下当从Launcher启动应用程序Activity时都带有FLAG_ACTIVITY_RESET_TASK_IF_NEEDED这样Task中所有此Activity上面的Activity都将被finish。这个标志就是辅助完成这个功能的。FLAG_ACTIVITY_NO_USER_ACTION Activity中的onUserLeaveHint回调用于指示用户将要离开它会退出前台。某些情况下这并不是用户主动选择造成的。比如当系统有来电Incoming Call或者闹钟事件由此弹出的Activity都不是用户主动去点击启动的因而带上这个标志可以使前述的回调函数不得到执行。FLAG_ACTIVITY_REORDER_TO_FRONT 设置此标志后如果将要启动的Activity已经在History Stack中运行那么我们只是调整其中的顺序将其放到最前端。FLAG_ACTIVITY_NO_ANIMATION 此标志表示启动的Activity不需要应用动画效果。FLAG_ACTIVITY_CLEAR_TASK 此标志将清除与启动的Activity相关task中的其他元素只能与FLAG_ACTIVITY_NEW_TASK一起用。FLAG_ACTIVITY_TASK_ON_HOME 新启动的Activity将被放在task中Launcher的上面如果存在的话这样它返回时就会是Launcher了。此标志只能与FLAG_ACTIVITY_NEW_TASK一起用。