在 Android 系统中,启动一个应用程序可以分为三种启动方式:热启动
、冷启动
和温启动
。它们分别表示了不同的启动方式和启动过程。
热启动是指在已经打开并处于后台运行的应用程序中,再次通过图标进入应用程序的启动方式。这时应用程序的进程已经存在,系统只是将应用程序从后台调到前台,会尽可能地重用上一次打开的 Activity 实例以及其他资源,启动速度最快。
冷启动是指启动一个之前没有启动过的应用程序。这种启动方式需要重新启动应用的进程,重新加载所有资源。在这个过程中,系统会进行以下步骤:
加载应用程序的代码和资源文件;
创建应用程序进程并启动其主线程;
执行 Application 的 onCreate 方法;
加载启动 Activity 的布局文件,创建 Activity 实例并执行 onCreate 方法。
由于启动过程中需要重新加载资源,因此冷启动的时间较长。
温启动是指在应用程序处于后台运行时,重新启动它。这种启动方式与热启动类似,但是由于应用程序在后台运行时,其占用的系统资源可能已经被清理或放入休眠状态,因此相对于热启动,温启动还需要额外的资源来唤醒应用程序进程和其他资源,启动速度较慢。
一个 Activity 只能属于一个任务,但一个任务可以包含多个 Activity。这些 Activity 组成了一个栈,在一个任务中,它们按照启动时间的先后顺序排列,称为任务栈。最后启动的 Activity 位于栈的最上方显示,用户可以看到它。在用户按下返回按钮时,当前 Activity 将会被销毁并出栈,系统会显示出上一个 Activity。
Android 提供了多种启动模式和 Intent 标记,我们可以通过它们来控制 Activity 的启动方式和与栈的交互方式,以满足不同的业务需求。例如,常见的启动模式包括 standard
、singleTop
、singleTask
和 singleInstance
当我们启动一个新的 Activity 时,Android 系统会根据启动模式和Manifest文件中的配置规则来决定如何创建和管理 Activity。
如果启动模式为 standard
,则会在当前任务栈中启动一个新的 Activity,并将其放在栈的顶部;
如果启动模式为 singleTop
,则会查找当前任务栈顶部是否已经存在相同类型的 Activity,如果存在,则直接调用该 Activity 的 onNewIntent 方法,并将其置顶;
如果启动模式为 singleTask
,则系统会检查当前存在的任务栈中是否已经存在相同类型的 Activity,如果存在,则直接切换到该任务栈并将其位于栈顶,如果不存在,则新建一个任务栈并将该 Activity 放入其中;
如果启动模式为 singleInstance
,则相当于 singleTask,但是它会单独创建一个新的任务栈,并且该任务栈中只能存在一个该类型的 Activity。
在 Android 开发中,Intent 是一种用于描述某个动作或意图的对象,可以用来启动 Activity、启动 Service、发送广播等操作。而 Intent 标记(Flags)则是用来修改 Intent 的行为的一种机制,可以通过添加标记来改变 Intent 的默认行为,例如改变启动模式、设置 Intent 的优先级等。
常见的 Intent 标记包括:
FLAG_ACTIVITY_NEW_TASK
该标记通常与启动 Activity 时一起使用,用于将新的 Activity 放入一个新的任务栈中,并使其成为栈顶的 Activity。如果该 Activity 已经存在于任务栈中,则会使该 Activity 后面的 Activity 出栈并销毁。
FLAG_ACTIVITY_CLEAR_TOP
该标记用于启动一个 Activity 后,清空该 Activity 顶部所有的 Activity,使得当前 Activity 位于该任务栈的栈顶。
FLAG_ACTIVITY_SINGLE_TOP
该标记用于启动一个 Activity 后,如果该 Activity 已经位于任务栈的栈顶,则不再创建新的 Activity,直接调用该 Activity 的 onNewIntent 方法。
FLAG_ACTIVITY_NO_HISTORY
该标记用于启动一个 Activity 后,使得该 Activity 不保留在任务栈中,当用户离开该 Activity 时,该 Activity 会被销毁并移出任务栈。
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
该标记用于启动一个 Activity 后,将该 Activity 从“最近使用应用程序”列表中移除,不会显示在系统的任务切换器中。
FLAG_ACTIVITY_BROUGHT_TO_FRONT
该标记用于启动一个 Activity 后,如果该 Activity 已经存在于任务栈中,将该 Activity 移动到任务栈的前台。
FLAG_ACTIVITY_CLEAR_TASK
该标记用于启动一个 Activity 后,清空当前任务栈中的所有 Activity,并将该 Activity 放入任务栈的底部。通常与 FLAG_ACTIVITY_NEW_TASK 一起使用。
FLAG_ACTIVITY_REORDER_TO_FRONT
该标记用于启动一个 Activity 后,将该 Activity 移动到任务栈的前台,并调整其它 Activity 的位置,以满足其在栈中的新位置。
当启动一个新的 Android 应用程序时,系统会经历以下步骤:
1.点击程序图标
Android 系统会根据应用程序的包名和要启动的 Activity 名称创建一个 Intent
对象,并将该 Intent 对象发送给 AMS
(ActivityManagerService)。这个过程实际上是通过 Binder 机制进行实现的。AMS 是 Android 系统中一个系统服务,负责管理 Activity 组件的生命周期。由SystemService启动AMS。
2.判断程序是否存在
当 AMS 接收到启动应用程序的 Intent 对象后,会检查该 Intent 对象所要启动的应用程序进程是否已经存在。如果已经存在,则 AMS 会直接通过 Binder 与该进程进行通信;否则会通过Socket通知Zygote 进程,Zygote 作为孵化器,会Fork
创建新的应用程序进程。
3.进程绑定
在新的应用程序进程中,AMS 会与 ActivityThread 通过 Binder 进行绑定。ActivityThread 是 Android 系统中的主线程,它负责将用户的操作转化为对应的任务,然后将任务分发给具体的组件进行处理。在绑定完成之后,AMS 会向 ActivityThread 发送一个 BIND_APPLICATION 命令,由 ActivityThread 进行处理。
4.发送启动应用程序命令
在 ActivityThread 中,系统会先调用 Looper.prepare() 方法创建消息循环队列,然后通过 ApplicationThreadProxy 向 AMS 发送一个启动应用程序的命令。AMS 收到该命令后会检查当前应用程序进程的状态,确定该进程是否处于空闲状态。如果是,AMS 会通过 Binder 向应用程序进程发送一个 LAUNCH_ACTIVITY 命令,并附带要启动的 Activity 对象。
5.创建任务栈
在应用程序进程中,通过 AMS 传来的 Activity 对象,系统会调用该 Activity 的构造函数进行初始化,并将该 Activity 添加到任务栈中。如果任务栈不存在,则会新创建一个任务栈。
6.处理任务
系统会根据该 Activity 的启动模式以及任务栈的状态,确定该 Activity 在任务栈中的位置。然后会将该 Activity 对象封装成 Intent 对象,并通过 Binder 机制发给 AMS。AMS 收到该 Intent 后,会检查该 Intent 所对应的任务栈是否在前台,如果在前台则不做处理,否则 AMS 会将该 Intent 封装成 ActivityStack 事件并放入消息队列中等待处理。
7.创建Activity
在 ActivityThread 中,当处理到该事件时,系统会调用 Instrumentation 的 callActivityOnCreate 方法,开始创建该 Activity 的视图布局。此后,系统会按照生命周期顺序依次调用各个方法,例如 onResume、onPause 等,直至该 Activity 销毁。
应用程序中启动一个新的 Activity 时,系统会经历以下步骤:
1.在当前Activity中调用startActivity()
方法,将要启动的Activity类的类名封装为Intent
对象,并调用startActivity()方法发送Intent。
2.系统会根据Intent中的信息,通过PackageManager
(包管理器)查询该Activity的信息,包括Activity所在的应用程序的包名、Activity的启动模式以及其他信息。
3.判断该Activity是否要启动到新的任务栈中,如果不是,将该Activity对象压入目标任务栈的栈顶。否则AMS
(ActivityManagerService)会创建一个新的任务栈,并将该Activity对象压入该任务栈中;AMS实通过调用ActivityStackSuperviso
r的createStack()
方法来创建新的Activity栈,并把该栈添加到ActivityStackSupervisor中维护的栈列表中。
4.AMS会将该Activity对象封装成Intent
对象(包括AMS创建的任务栈的唯一标识符,用于标识该任务栈的ID)。并通过Binder
机制发送给应用程序进程,由ActivityThread
进行处理。
5.在应用程序进程中,ActivityThread
接收到AMS发送来的Intent后,会根据Intent中的信息,创建一个新的Activity实例,ActivityThread会根据AMS返回的任务栈ID
,来确定新Activity所在的任务栈。如果任务栈ID为-1,说明该Activity不需要启动到新的任务栈中,而是在当前任务栈中启动。否则,ActivityThread会将该Activity的启动标志设置为“FLAG_ACTIVITY_NEW_TASK
”,这样就会启动到一个新的任务栈中。调用其onCreate()
方法进行初始化。此时,该Activity还没有显示出来,只是存在于内存中。
6.最后,系统会调用新启动的Activity的onStart()
、onResume()
方法,让其显示出来并进入可见状态。
相同点:
都需要经过AMS
(Activity Manager Service)进行统一调度和管理。
都需要在应用程序进程中创建相应的组件实例
,并进行初始化。
在启动过程中都需要通过Intent
来传递相应的参数和信息。
不同点:
App启动流程是整个应用程序
从闲置状态到完全启动运行的流程,包含了多个Activity的启动和相应服务、广播等组件的启动;而Activity启动流程是单个Activity
的启动过程。
App启动流程涉及到的组件较为复杂
,包括了Application、Activity、Service等多种组件类型的启动和运行;而Activity启动流程是指在Activity栈中启动一个新的Activity
实例。
App启动流程通常是由系统启动,或者由用户手动触发
启动;而Activity启动流程则是由当前Activity中的代码主动调用
startActivity()方法来触发启动。
在启动过程中,App需要先执行Application的onCreate()
方法,然后才会启动第一个Activity;而Activity的启动过程则是直接调用所需Activity的onCreate()
方法。
在启动过程中,App会经历多个Activity的启动和销毁
过程,会涉及到Activity栈和任务栈等概念;而Activity的启动流程则只关注单个Activity
的启动过程。