Activity Process Task Application 专题讲解

Activity Process Task Application 专题讲解

 

Activity、和进程

 为了阅读方便,将文档转成pdf 

https://files.cnblogs.com/franksunny/ActivityTask%E5%BA%94%E7%94%A8%E5%92%8C%E8%BF%9B%E7%A8%8B%E5%B0%8F%E7%BB%93.pdf

Activity、和进程

很想弄清楚启动一个ActivityTask(任务)的关系,网上也有很多相关资料,由从源码来具体分析的,也有针对launchmode来分析,但都不是自己的,理解起来总不是那么容易,为此,尝试着自己去理解其中的逻辑。不过事先需要弄清楚两个问题:

谁负责管理Activity?

和android\server\am下面的Ams源码Task到底是什么?

根据对上面问题的解答,既然Activity是由Ams通过ActivityStack来管理的,那么这个和功能。而android程序,仍然使用一个apk工程一个Application的开发形式,但是对于Aplication的开发就用到了Activity、service等四大组件,其中的每一个组件,都是可以被跨应用复用的哦,这个就是android强化了组件概念,弱化了Aplication的概念,所以在Task就是来负责实现这个功能的,它是从用户角度来理解应用而建立的一个抽象概念。因为用户所能看到的组件就是Activity,所以Task栈,Activity还是通过ActivityStack来管理,在ActivityRecord中有一个TaskRecord对象记录了真实的Activity实例是属于哪个Task通过一个int类型的TaskId来唯一标识,该值在手机重启时将会被置零。

说了这么多,还是找一个Task任务自始至终都是从用户的角度出发而设计的概念,保证用户的调用逻辑。

Activity、Application与进程的关系

理清楚了上述两个概念问题,进入Activity的启动与和进程的关系。对Activity启动过程具体的分析,工程耗时很庞大,网上有个老罗整理的三篇博客,我看了半天还是云里雾里的,有兴趣的可以查看如下链接:http://blog.csdn.net/luoshengyang/article/details/6685853。我通过我现在的认识android:和启动它的组件所属的TaskId一直,但是也不尽然,这就要看下面的具体分析了。

另外通过对service的应用,可以得出结论,一个apk,即一个应用(Application)可以跑在多个进程中,一个进程在一个虚拟机中运行,也即一个apk可以启动多个虚拟机。

通过shareuserID可以将多个apk,跑在同一个进程中。

从而得出结论:一个虚拟机只能跑一个进程,一个进程里可以跑多个应用,一个应用也可以跑在多个进程中,这就是他们的关系。

ActivityTask的关系

启动一个Activity有两种方式,一种就是通过Launcher,另外一种是通过程序代码调用startActivity函数实现(验证过 AppWidget其实与这种方式是一致的)其实影响Activity启动关键点大致有三个因素:Activity注册信息中的launchMode、启 动Activity时Intent中的launchFlagsandroid:launchMode 属性进行设置的方式,共有四种模式可以设置,分别是standard、singleTop、singleTask、singleInstance,下面分 别阐述之(由于其中几种因素有设置时,会影响lauchMode的四种模式,所以下面情况下,其它因素都是缺省不设置的情况)。

standard

standard是默认模式,即假设用户在manifest中对Activity不指定Task栈 的根实例),那么在通过桌面长按,在近期任务中跳转到Activity所在的任务时,即使该Activity实例不是在栈顶,也会被置到栈顶(还会调用其 onNewIntent函数),并将AS上同TaskId的其它Activity实例销毁,具体可以通过附带的demo来验证,其中TaskOne中的 Activity1置成singleTask启动模式,其它均为默认的standard,其log输出如下:

//在TaskTwo中启动Activity1,此前TaskOne apk没有在运行,所以启动Activity1时会申请一个新的TaskId,2afcfbd8这个Activity1成为了TaskId为53的Task栈栈底实例

04-05 16:21:27.144: E/ActivityB @2b003230(17933): onPause pid 17933 taskid 52

04-05 16:21:27.404: E/Activity1 @2afcfbd8(18489): onCreate pid 18489 taskid 53

04-05 16:21:29.214: E/ActivityB @2afecaf0(17933): onCreate pid 17933 taskid 53

04-05 16:21:30.254: E/Activity2 @2afdeef0(18489): onCreate pid 18489 taskid 53

04-05 16:21:30.894: E/ActivityB @2aff9328(17933): onCreate pid 17933 taskid 53

04-05 16:21:31.454: E/Activity2 @2afe9330(18489): onCreate pid 18489 taskid 53

04-05 16:21:31.864: E/ActivityB @2b009910(17933): onCreate pid 17933 taskid 53

04-05 16:21:32.424: E/Activity2 @2aff2570(18489): onCreate pid 18489 taskid 53

 

//通过长按跳转到TaskOne任务,此时在AS中id为53的在Activity1上面有6个

04-05 16:22:35.144: E/ActivityB @2afecaf0(17933): onDestroy pid 17933 taskid 53

04-05 16:22:35.144: E/Activity2 @2afdeef0(18489): onDestroy pid 18489 taskid 53

04-05 16:22:35.234: E/ActivityB @2aff9328(17933): onDestroy pid 17933 taskid 53

04-05 16:22:35.254: E/Activity2 @2afe9330(18489): onDestroy pid 18489 taskid 53

04-05 16:22:35.324: E/ActivityB @2b009910(17933): onDestroy pid 17933 taskid 53

04-05 16:22:35.344: E/Activity2 @2aff2570(18489): onPause pid 18489 taskid 53

04-05 16:22:35.394: E/Activity1 @2afcfbd8(18489): onNewIntent pid 18489 taskid 53

04-05 16:22:35.394: E/Activity1 @2afcfbd8(18489): onStart pid 18489 taskid 53

04-05 16:22:35.394: E/Activity1 @2afcfbd8(18489): onResume pid 18489 taskid 53

04-05 16:22:35.524: E/Activity2 @2aff2570(18489): onStop pid 18489 taskid 53

04-05 16:22:35.524: E/Activity2 @2aff2570(18489): onDestroy pid 18489 taskid 53

singleInstance

启动一个以singleInstance为launchmode的Activity时,假如AS中已经有一个该类实例,那么调用其 onNewIntent函数;否则就会创建一个新的TaskId,与该Activity所在的apk进程完全不同的TaskId,而且这个TaskId值 以后也不会被用于其他任何Activity实例中。

简单小结

一般我们开发普通的应用程序时,我们只需要使用缺省的standard和singleInstance来声明注册的Activity,因为它将破坏用户感觉上的回退操作,给用户使用上带来迷惑,所以一般将这两者用于很耗资源的Activity,通过查看源码发现在源码packages\apps中的程序,有如下一些应用使用了这两者高级设置

AndroidManifest.xml (packages\apps\browser):                  android:name="AlertActivity" android:launchMode="singleTask"

AndroidManifest.xml (packages\apps\deskclock):                android:launchMode="singleInstance"

AndroidManifest.xml (packages\apps\deskclock):                android:launchMode="singleTask"

AndroidManifest.xml (packages\apps\launcher2):            android:launchMode="singleTask"

AndroidManifest.xml (packages\apps\phone):            android:launchMode="singleInstance">

AndroidManifest.xml (packages\apps\quicksearchbox):                  android:launchMode="singleTask"

AndroidManifest.xml (packages\providers\downloadprovider):                  Task有关的manifest文件中Activity的特性值介绍

Task移动到有着affinity的Task进入到前台时)

   “true”,表示能移动,“false”,表示它必须呆在启动时呆在的那个Task里。

    如果这个特性没有被设定,设定到<application>元素上的allowTaskReparenting特性的值会应用到Activity上。默认值为“false”。

    一般来说,当Activity启动后,它就与启动它的Task不再显示时,你可以使用这个特性来强制Activity移动到有着affinity的Task中。

    例如,如果 email中包含一个web页的链接,点击它就会启动一个Activity来显示这个页面。这个Activity是由Browser应用程序定义的,但是,现在它作为email Task里,当Browser下一次进入到前台时,它就能被看见,并且,当email Task的affinity是通过读取根Activity的affinity决定。因此,根Activity总是位于相同affinity的和“singleInstance”的Activity只能位于和“singleTop”模式。

Task的状态是否总是由系统来保持。

    “true”,表示总是;“false”,表示在某种情形下允许系统恢复Task的根Activity有意义;对其它Activity来说,忽略之。

    一般来说,特定的情形如当用户从主画面重新选择这个Task进行清理(从stack中删除位于根Activity之上的所有Activivity)。典型的情况,当用户有一段时间没有访问这个Task的最新状态,无论他们是如何启动的。这非常有用,例如,像Browser应用程序,这里有很多的状态(例如多个打开的Tab),用户不想丢失这些状态。

Task中清除所有的Activity,除了根Activity外(每当从主画面重新启动时)

   “true”,表示总是清除至它的根Activity,“false”表示不。默认值是“false”。

    这个特性只对启动一个新的Task中其它的Activity忽略。

    当这个值为“true”,每次用户重新启动这个Task最后在做些什么,也不管用户是使用BACK还是HOME离开的。当这个值为“false”时,可能会在一些情形下(参考alwaysRetainTaskState特性)清除Task中最后工作的内容。然而,如果P设定这个特性为“true”,当用户按下HOME并使这个Task时,用户只能看到P。

    如果这个特性Task中;剩下的Activity都将被抛弃,如上所述。

Task(在主画面选择这个Task)时已经存在的Activity实例是否要关闭(结束)

   “true”,表示应该关闭,“false”表示不关闭。默认值是“false”。

    如果这个特性android:launchMode

    用于指示Activity如何启动。这里有四种模式,与Intent对象中的Activity Flags(FLAG_ACTIVITY_*变量)共同作用,来决定Activity如何启动来处理Intent。它们是:

    "standard"

    "singleTop"

    "singleTask"

    "singleInstance"

    默认模式是“standard”。

    前面文章:“android:noHistory

    用于标记当用户从Activity上离开并且它在屏幕上不再可见时Activity是否从Activity stack中清除并结束(调用finish()方法)——“true”,表示它应该关闭,“false”,表示不需要。默认值是“false”。

    “true”值意味着Activity不会留下历史痕迹。因为它不会在Activity stack的Task中保留,因此,用户不能返回它。

    比如启用界面的就可以借用这个。

android:taskAffinity

   这就是本文所描述的任务共用性。

   Activity为Task(在用户的角度是相同的“应用程序”)。Task(参考allowTaskReparenting特性)TASK标志启动的Activity宿主的Task中。为了明确Activity不宿主特定的Task,设定该特性为空的字符串。

    如果这个特性没有设置,Activity将从应用程序的设定那里继承下来(参考<application>元素的taskAffinity特 性)。应用程序默认的affinity的名字是<manifest>元素中设定的package名。

跟Task有关的Intent对象中设置的Flag

FLAG_ACTIVITY_BROUGHT_TO_FRONT

    这个标志一般不是由程序代码设置的,如在launchMode中设置singleTask模式时系统帮你设定。

FLAG_ACTIVITY_CLEAR_TOP

    如果设置,并且这个Activity已经在当前的Task中包含这些Activity:A,B,C,D。如果D调用了startActivity(),并且包含一个指向Activity B的Intent,那么,C和D都将结束,然后B接收到这个Intent,因此,目前stack的状况是:A,B。

    上例中正在运行的Activity B既可以在onNewIntent()中接收到这个新的Intent,也可以把自己关闭然后重新启动来接收这个Intent。如果它的启动模式声明为 “multiple”(默认值),并且你没有在这个Intent中设置FLAG_ACTIVITY_SINGLE_TOP标志,那么它将关闭然后重新创 建;对于其它的启动模式,或者在这个Intent中设置FLAG_ACTIVITY_SINGLE_TOP标志,都将把这个Intent投递到当前这个实 例的onNewIntent()中。

    这个启动模式还可以与FLAG_ACTIVITY_NEW_Task中的根Activity,它会把那个TASK_RESET

    如果设置,这将在Task恢复时,需要清理Activity。也就是说,下一次TASK_IF_NEEDED标记进入前台时(典型的操作是用户在主画面重启它),这个ActivityTask的一部分,因为这是用户在这个Task,然后从主画面选择e-mail app,我们可能希望回到查看的会话中,但不是查看图片附件,因为这让人困惑。通过在启动图片浏览时设定这个标志,浏览及其它启动的Activity在下次用户返回到mail程序时都将全部清除。

FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS

    如果设置,新的Activity不会在最近启动的Activity的列表中保存。

FLAG_ACTIVITY_FORWARD_RESULT

    如果设置,并且这个Intent用于从一个存在的Activity启动一个新的Activity,那么,这个作为答复目标的Activity将会传到这个 新的Activity中。这种方式下,新的Activity可以调用setResult(int),并且这个结果值将发送给那个作为答复目标的 Activity。

FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY

    这个标志一般不由应用程序代码设置,如果这个Activity是从历史记录里启动的(常按HOME键),那么,系统会帮你设定。

FLAG_ACTIVITY_MULTIPLE_TASK结合起来使用,可以禁用把已存的Task总是会启动来处理Intent,而不管这是是否已经有一个Task管理功能,因此,你不应该使用这个标志,除非你提供给用户一种方式可以返回到已经启动的TASK标志没有设置,这个标志被忽略。

FLAG_ACTIVITY_NEW_Task的开始。一个Task中的Activity)定义了用户可以迁移的Activity原子组。和后台;在某个特定Task中的所有Activity总是保持相同的次序。

    这个标志一般用于呈现“启动”类型的行为:它们提供用户一系列可以单独完成的事情,与启动它们的Activity完全无关。

    使用这个标志,如果正在启动的Activity的Task会简单的移入前台。参考FLAG_ACTIVITY_MULTIPLE_TASK标志,可以禁用这一行为。

    这个标志不能用于调用方对已经启动的Activity请求结果。

FLAG_ACTIVITY_NO_ANIMATION

    如果在Intent中设置,并传递给Context.startActivity()的话,这个标志将阻止系统进入下一个Activity时应用 Acitivity迁移动画。这并不意味着动画将永不运行——如果另一个Activity在启动显示之前,没有指定这个标志,那么,动画将被应用。这个标 志可以很好的用于执行一连串的操作,而动画被看作是更高一级的事件的驱动。

FLAG_ACTIVITY_NO_HISTORY

    如果设置,新的Activity将不再历史stack中保留。用户一离开它,这个Activity就关闭了。这也可以通过设置noHistory特性。

FLAG_ACTIVITY_NO_USER_ACTION

    如果设置,作为新启动的Activity进入前台时,这个标志将在Activity暂停之前阻止从最前方的Activity回调的onUserLeaveHint()。

    典型的,一个Activity可以依赖这个回调指明显式的用户动作引起的Activity移出后台。这个回调在Activity的生命周期中标记一个合适的点,并关闭一些Notification。

    如果一个Activity通过非用户驱动的事件,如来电或闹钟,启动的,这个标志也应该传递给Context.startActivity,保证暂停的Activity不认为用户已经知晓其Notification。

FLAG_ACTIVITY_PREVIOUS_IS_TOP

    If set and this intent is being used to launch a new activity from an existing one, the current activity will not be counted as the top activity for deciding whether the new intent should be delivered to the top instead of starting a new one. The previous activity will be used as the top, with the assumption being that the current activity will finish itself immediately.

FLAG_ACTIVITY_REORDER_TO_FRONT

    如果在Intent中设置,并传递给Context.startActivity(),这个标志将引发已经运行的Activity移动到历史stack的顶端。

    例如,假设一个TASK_IF_NEEDED

If set, and this activity is either being started in a new task, then it will be launched as the front door of the task in the proper state (either moving activities to or from it), or simply resetting that task to its initial state if needed.

FLAG_ACTIVITY_SINGLE_TOP

    如果设置,当这个Activity位于历史stack的顶端运行时,不再启动一个新的。

 
posted @ 2014-11-27 15:51  狐狸已化妖  阅读(770)  评论(0编辑  收藏  举报