android启动分析
A. Android —— Activity的四种启动模式
除了Activity的生命周期外,Activity的启动模式也是一个难点,有时候为了满足项目的特殊需求,就必须使用Activity的启动模式。
在默认情况下,当我们多次启动同一个Activity的时候,系统会创建多个实例并把它们放入任务栈中,但是有些场景重复创建多个实例,是没有必要且浪费资源的,这就需要启动模式来修改系统的默认行为。
下面,我将以理论+实践的形式为大家介绍Activity的启动模式。
这是系统的默认启动模式,采用这种模式的Activity无论是否已经存在实例,都会重新创建一个实例,在这种模式下谁启动了这个Activity,那么这个Activity就运行在启动它的那个Activity所在的栈中。
实践:MainActivity 采用 standard 模式
在这种模式下,如果新的Activity已经位于任务栈的栈顶,那么此Activity不会被重新创建,同时它的 NewIntent 方法将会被回调。如果新Activity的实例已存在但不是位于栈顶,那么新Activity依然会被创建。
实践:MainActivity 采用 singleTop 模式
MainActivity 采用 singleTop 模式,SecondActivity采用 standard 模式
这是一种单实例模式,在这种模式下,只要Activity在一个栈中存在,那么多次启动此Activity都不会重新创建实例,而是回调 onNewIntent() 。
实践:MainActivity 采用 singleTask 模式
MainActivity 采用 singleTask 模式,SecondActivity采用 standard 模式
这是一种加强的 singleTask 模式,它除了具有 singleTask 模式的所有特性外,还加强了一点,那就是具有此模式的Activity只能单独的位于一个任务栈中。
实践:MainActivity 采用 singleInstance 模式
MainActivity 采用 singleInstance 模式,SecondActivity采用 standard 模式
以上就是Activity启动模式的介绍。
欢迎留言指出错误。
B. 如何优化 android 系统应用的启动速度
一、应用的启动
启动方式
通常来说,在安卓中应用的启动方式分为两种:冷启动和热启动。
1、冷启动:当启动应用时,后台没有该应用的进程,这时系统会重新创建一个新的进程分配给该应用,这个启动方式就是冷启动。
2、热启动:当启动应用时,后台已有该应用的进程(例:按back键、home键,应用虽然会退出,但是该应用的进程是依然会保留在后台,可进入任务列表查看),所以在已有进程的情况下,这种启动会从已有的进程中来启动应用,这个方式叫热启动。
- adb shell am start -W [packageName]/[packageName.MainActivity]
特点
1、冷启动:冷启动因为系统会重新创建一个新的进程分配给它,所以会先创建和初始化Application类,再创建和初始化MainActivity类(包括一系列的测量、布局、绘制),最后显示在界面上。
2、热启动:热启动因为会从已有的进程中来启动,所以热启动就不会走Application这步了,而是直接走MainActivity(包括一系列的测量、布局、绘制),所以热启动的过程只需要创建和初始化一个MainActivity就行了,而不必创建和初始化Application,因为一个应用从新进程的创建到进程的销毁,Application只会初始化一次。
上面说的启动是点击app的启动图标来启动的,而另外一种方式是进入最近使用的列表界面来启动应用,这种不应该叫启动,应该叫恢复。
二、应用启动的流程
在安卓系统上,应用在没有进程的情况下,应用的启动都是这样一个流程:当点击app的启动图标时,安卓系统会从Zygote进程中fork创建出一个新的进程分配给该应用,之后会依次创建和初始化Application类、创建MainActivity类、加载主题样式Theme中的windowBackground等属性设置给MainActivity以及配置Activity层级上的一些属性、再inflate布局、当onCreate/onStart/onResume方法都走完了后最后才进行contentView的measure/layout/draw显示在界面上,所以直到这里,应用的第一次启动才算完成,这时候我们看到的界面也就是所说的第一帧。
所以,总结一下,应用的启动流程如下:
Application的构造器方法——>attachBaseContext()——>onCreate()——>Activity的构造方法——>onCreate()——>配置主题中背景等属性——>onStart()——>onResume()——>测量布局绘制显示在界面上。
三、测量应用启动的时间
在上面这个启动流程中,任何一个地方有耗时操作都会拖慢我们应用的启动速度,而应用启动时间是用毫秒度量的,对于毫秒级别的快慢度量我们还是需要去精确的测量到到底应用启动花了多少时间,而根据这个时间来做衡量。
什么才是应用的启动时间
从点击应用的启动图标开始创建出一个新的进程直到我们看到了界面的第一帧,这段时间就是应用的启动时间。
我们要测量的也就是这段时间,测量这段时间可以通过adb shell命令的方式进行测量,这种方法测量的最为精确,命令为:
执行成功后将返回三个测量到的时间:
1、ThisTime:一般和TotalTime时间一样,除非在应用启动时开了一个透明的Activity预先处理一些事再显示出主Activity,这样将比TotalTime小。
2、TotalTime:应用的启动时间,包括创建进程+Application初始化+Activity初始化到界面显示。
3、WaitTime:一般比TotalTime大点,包括系统影响的耗时。
下面是测量一个应用冷启动和热启动的时间:
冷启动:
热启动:
以上就是本文的全部内容,希望对大家学习Android软件编程有所帮助。
C. Android系统启动之init.rc文件解析过程
第一篇: Android系统启动之bootloader
第二篇: Android系统启动之Init流程(上)
第三篇: Android系统启动之Init流程(下)
第四篇: Android系统启动之init.rc文件解析过程
第五篇: Android系统启动之zyogte进程
第六篇: Android系判哗统启动之zyogte进程java(上)
第七篇: Android系统启动之zyogte进程java(下)
第八篇: Android系统启动之SystemServer
Android init.rc文件由系统第一个启动的init程序解析。是启动系统服务使用的文件。
主要包含了四种类型的语句:
Action和services显式声明了一个语句块,而commands和options属于最近声明的语句块。
在第一个语句块之前 的commands和options会被忽略.
基本规则如下:
动掘蚂行作表示了一组命令(commands)组成.动作包括一个触发器,决定了何时运行这个动作。
注意: 当触发器的条件满足时,这个动作会被增加到已被运行的队列尾。假设此动作在队列中已经存在,那么它将不会运行.
一个动作所包括的命令将被依次运行。
在"动作"(action)里面的,on后面物隐跟着的字符串是触发器(trigger),trigger是一个用于匹配某种事件类型的字符串,它将对应的Action的执行。
触发器(trigger)有几种格式:
常见的格式:
command是action的命令列表中的命令,或者是service中的选项 onrestart 的参数命令.
命令将在所属事件发生时被一个个地执行.
常见命令:
服务是指那些须要在系统初始化时就启动或退出时自己主动重新启动的程序.
解释一下各个参数:
options是Service的修订项。它们决定一个服务何时以及如何运行.
使用例子:
源码路径 system/core/init/init.cpp 中:
开始解析rc文件.
ParseConfig函数在文件 core/init/init_parser.cpp 140行:
ParseConfigFile函数:
Android init.rc文件浅析
安卓系统启动--3init.rc解析
init.rc深入学习
D. Android启动过程深入解析
当按下Android设备电源键时究竟发生了什么?
Android的启动过程是怎么样的?
什么是linux内核?
桌面系统linux内核与Android系统linux内核有什么区别?
什么是引导装载程序?
什么是Zygote?
什么是X86以及ARM linux?
什么是init.rc?
什么是系统服务?
当我们想到Android启动过程时,脑海中总是冒出很多疑问。本文将介绍Android的启动过程,希望能帮助你找到上面这些问题的答案。
Android是一个基于Linux的开源操作系统。x86(x86是一系列的基于intel 8086 CPU的计算机微处理器指令集架构)是linux内核部署最常见的系统。然而,所有的Android设备都是运行在ARM处理器(ARM 源自进阶精简指令集机器,源自ARM架构)上,除了英特尔的Xolo设备(http://xolo.in/xolo-x900-features)。Xolo来源自凌动1.6GHz x86处理器。Android设备或者嵌入设备或者基于linux的ARM设备的启动过程与桌面版本相比稍微有些差别。这篇文章中,我将解释Android设备的启动过程。深入linux启动过程是一篇讲桌面linux启动过程的好文。
当你按下电源开关后Android设备执行了以下步骤。
此处图片中step2中的一个单词拼写错了,Boot Loaeder应该为Boot Loader(多谢@jameslast 提醒)
第一步:启动电源以及系统启动
当电源按下,引导芯片代码开始从预定义的地方(固化在ROM)开始执行。加载引导程序到RAM,然后执行。
第二步:引导程序
引导程序是在Android操作系统开始运行前的一个小程序。引导程序是运行的第一个程序,因此它是针对特定的主板与芯片的。设备制造商要么使用很受欢迎的引导程序比如redboot、uboot、qi bootloader或者开发自己的引导程序,它不是Android操作系统的一部分。引导程序是OEM厂商或者运营商加锁和限制的地方。
引导程序分两个阶段执行。第一个阶段,检测外部的RAM以及加载对第二阶段有用的程序;第二阶段,引导程序设置网络、内存等等。这些对于运行内核是必要的,为了达到特殊的目标,引导程序可以根据配置参数或者输入数据设置内核。
Android引导程序可以在找到。
传统的加载器包含的个文件,需要在这里说明:
init.s初始化堆栈,清零BBS段,调用main.c的_main()函数;
main.c初始化硬件(闹钟、主板、键盘、控制台),创建linux标签。
更多关于Android引导程序的可以在这里了解。
第三步:内核
Android内核与桌面linux内核启动的方式差不多。内核启动时,设置缓存、被保护存储器、计划列表,加载驱动。当内核完成系统设置,它首先在系统文件中寻找”init”文件,然后启动root进程或者系统的第一个进程。
第四步:init进程
init是第一个进程,我们可以说它是root进程或者说有进程的父进程。init进程有两个责任,一是挂载目录,比如/sys、/dev、/proc,二是运行init.rc脚本。
init进程可以在/system/core/init找到。
init.rc文件可以在/system/core/rootdir/init.rc找到。
readme.txt可以在/system/core/init/readme.txt找到。
对于init.rc文件,Android中有特定的格式以及规则。在Android中,我们叫做Android初始化语言。
Action(动作):动作是以命令流程命名的,有一个触发器决定动作是否发生。
语法
1
2
3
4
5
; html-script: false ]
on <trigger>
<command>
<command>
<command>
Service(服务):服务是init进程启动的程序、当服务退出时init进程会视情况重启服务。
语法
1
2
3
4
5
; html-script: false ]
service <name> <pathname> [<argument>]*
<option>
<option>
...
Options(选项)
选项是对服务的描述。它们影响init进程如何以及何时启动服务。
咱们来看看默认的init.rc文件。这里我只列出了主要的事件以及服务。
Table
Action/Service
描述
on early-init
设置init进程以及它创建的子进程的优先级,设置init进程的安全环境
on init
设置全局环境,为cpu accounting创建cgroup(资源控制)挂载点
on fs
挂载mtd分区
on post-fs
改变系统目录的访问权限
on post-fs-data
改变/data目录以及它的子目录的访问权限
on boot
基本网络的初始化,内存管理等等
service servicemanager
启动系统管理器管理所有的本地服务,比如位置、音频、Shared preference等等…
service zygote
启动zygote作为应用进程
在这个阶段你可以在设备的屏幕上看到“Android”logo了。
第五步
在Java中,我们知道不同的虚拟机实例会为不同的应用分配不同的内存。假如Android应用应该尽可能快地启动,但如果Android系统为每一个应用启动不同的Dalvik虚拟机实例,就会消耗大量的内存以及时间。因此,为了克服这个问题,Android系统创造了”Zygote”。Zygote让Dalvik虚拟机共享代码、低内存占用以及最小的启动时间成为可能。Zygote是一个虚拟器进程,正如我们在前一个步骤所说的在系统引导的时候启动。Zygote预加载以及初始化核心库类。通常,这些核心类一般是只读的,也是Android SDK或者核心框架的一部分。在Java虚拟机中,每一个实例都有它自己的核心库类文件和堆对象的拷贝。
Zygote加载进程
加载ZygoteInit类,源代码:/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
registerZygoteSocket()为zygote命令连接注册一个服务器套接字。
preloadClassed “preloaded-classes”是一个简单的包含一系列需要预加载类的文本文件,你可以在/frameworks/base找到“preloaded-classes”文件。
preloadResources() preloadResources也意味着本地主题、布局以及android.R文件中包含的所有东西都会用这个方法加载。
在这个阶段,你可以看到启动动画。
第六步:系统服务或服务
完成了上面几步之后,运行环境请求Zygote运行系统服务。系统服务同时使用native以及java编写,系统服务可以认为是一个进程。同一个系统服务在Android SDK可以以System Services形式获得。系统服务包含了所有的System Services。
Zygote创建新的进程去启动系统服务。你可以在ZygoteInit类的”startSystemServer”方法中找到源代码。
核心服务:
启动电源管理器;
创建Activity管理器;
启动电话注册;
启动包管理器;
设置Activity管理服务为系统进程;
启动上下文管理器;
启动系统Context Providers;
启动电池服务;
启动定时管理器;
启动传感服务;
启动窗口管理器;
启动蓝牙服务;
启动挂载服务。
其他服务:
启动状态栏服务;
启动硬件服务;
启动网络状态服务;
启动网络连接服务;
启动通知管理器;
启动设备存储监视服务;
启动定位管理器;
启动搜索服务;
启动剪切板服务;
启动登记服务;
启动壁纸服务;
启动音频服务;
启动耳机监听;
启动AdbSettingsObserver(处理adb命令)。
第七步:引导完成
一旦系统服务在内存中跑起来了,Android就完成了引导过程。在这个时候“ACTION_BOOT_COMPLETED”开机启动广播就会发出去。
E. Android系统的几种启动模式
1.一般启动模式(normal mode) 进入方法:按电源键启动 描述:这是正常启动手机的方法 2.安全模式(safe mode) 进入方法:按住menu键,按电源键启动手机,直至手机启动完成松开menu键 描述:和正常启动一样,但没有登记Google,所以不能访问Market或使用你的Google账号 3.引导模式(bootloader mode) 进入方法:按住照相键,按电源键启动手机 描述:可以从SD卡上安装新的系统映像(DREAIMG.NBH),只需再按一次电源键。为获取root权限,对手机进行降级,就是使用这个模式。 4.恢复模式(recovery mode) 进入方法:按住HOME键,按电源键启动手机 描述:可以打开命令解释程序(shell),刷新映像文件(flash image),执行备份等。当然这一切取决于你手机上的recovery image版本。 5.诊断模式(diagnostic mode) 进入方法:按住轨迹球,按电源键启动手机 描述:用于测试(按音量键选择项目) 6.fastboot模式 进入方法:按住返回键,按电源键启动手机,直至屏幕出现FASTBOOT字样后松开返回键
F. Android Activity启动模式与状态保存及恢复详解
Activity是 Android组件 中最基本也是最为常见用的四大组件(Activity,Service服务,Content Provider内容提供者,BroadcastReceiver广播接收器)之一 。
Activity是一个应用程序 组件 ,提供一个 屏幕 ,用户可以用来交互为了完成某项任务。
Activity中所有操作都与用户密切相关,是一个负责与 用户交互 的组件,可以通过setContentView(View)来 显示指定控件 。
在一个android应用中,一个Activity通常就是一个单独的屏幕,它上面可以显示一些控件也可以监听并处理用户的事件做出响应。Activity之间通过Intent进行通信。
关于Activity启动流程请参考之前的文章 Android activity启动流程分析
activity有四种启动模式,分别为standard,singleTop,singleTask,singleInstance。如果要使用这四种启动模式,必须在manifest文件中<activity>标签中的launchMode属性中配置。
标准的默认启动模式,这种模式下activity可以被多次实例化,即在一个task中可以存在多个activity,每一个activity会处理一个intent对象,(在A中再次启动A,会存在后面的A在前面的A上面,当前task会存在两个activity的实例对象)
如果一个singleTop模式启动的activity实例已经存在于栈顶,那么再次启动这个activity的时候,不会重新创建实例,而是重用位于栈顶的那个实例,并且会调用实例的onNewIntent()方法将Intent对象传递到这个实例中,如果实例不位于栈顶,会创建新的实例。
启动模式设置为singleTask,framework在启动该activity时只会把它标示为可在一个新任务中启动,至于是否在一个新任务中启动,还要受其他条件的限制,即taskAffinity属性。
taskAffinity :默认情况下,一个应用中的所有activity具有相同的taskAffinity,即应用程序的包名。我们可以通过设置不同的taskAffinity属性给应用中的activity分组,也可以把不同的应用中的activity的taskAffinity设置成相同的值,当两个不同应用中的activity设置成相同的taskAffinity时,则两个activity会属于同一个TaskRecord。
在启动一个singleTask的Activity实例时,如果系统中已经存在这样一个实例,就会将这个实例调度到任务栈的栈顶,并清除它当前所在任务中位于它上面的所有的activity;如果这个已存在的任务中不存在一个要启动的Activity的实例,则在这个任务的顶端启动一个实例;若这个任务不存在,则会启动一个新的任务,在这个新的任务中启动这个singleTask模式的Activity的一个实例。
以singleInstance模式启动的Activity具有全局唯一性,即整个系统中只会存在一个这样的实例,如果在启动这样的Activiyt时,已经存在了一个实例,那么会把它所在的任务调度到前台,重用这个实例。
以singleInstance模式启动的Activity具有独占性,即它会独自占用一个任务,被他开启的任何activity都会运行在其他任务中(官方文档上的描述为,singleInstance模式的Activity不允许其他Activity和它共存在一个任务中)。
被singleInstance模式的Activity开启的其他activity,能够开启一个新任务,但不一定开启新的任务,也可能在已有的一个任务中开启,受条件的限制,这个条件是:当前系统中是不是已经有了一个activity B的taskAffinity属性指定的任务。
涉及到Activity启动,就不得不说一下Activity的管理,Activity是以什么方式及被什么类来进行管理的,涉及的类主要如下:
历史栈中的一个条目,代表一个activity。ActivityRecord中的成员变量task表示其所在的TaskRecord,ActivityRecord与TaskRecord建立了联系。
内部维护一个 ArrayList<ActivityRecord> 用来保存ActivityRecord,TaskRecord中的mStack表示其所在的ActivityStack,TaskRecord与ActivityStack建立了联系。
内部维护了一个 ArrayList<TaskRecord> ,用来管理TaskRecord,ActivityStack中持有ActivityStackSupervisor对象,由ActivityStackSupervisor创建。
负责所有ActivityStack的管理。内部管理了mHomeStack、mFocusedStack和mLastFocusedStack三个Activity栈。其中,mHomeStack管理的是Launcher相关的Activity栈;mFocusedStack管理的是当前显示在前台Activity的Activity栈;mLastFocusedStack管理的是上一次显示在前台Activity的Activity栈。
ActivityThread 运行在UI线程(主线程),App的真正入口。
用来实现AMS和ActivityThread之间的交互。
负责调用Activity和Application生命周期。
当一个Activity未被主动关闭,即“被动关闭”时,可能需要系统给用户提供保持一些状态的入口。
前面说的入口就是:Activity提供了onSaveInstanceState()方法,该方法是Activity在关闭前保存状态的核心方法。
前面提到“被动关闭”,如果是主动关闭那么就不会调用,比如:按back键、调用finish()等,那么"被动关闭"的场景有哪些呢?下面给列举一下:
肯定在调用onStop()前被调用,但不保证在onPause()前 / 后,一般是在onPause()后调用。
当需要保持状态时,在onSaveInstanceState()内执行以下逻辑:
当需要恢复时,在onCreate()内部执行以下逻辑:
布局每个View默认实现:onSaveInstanceState(),即UI的任何改变都会自动的存储和在activity重新创建的时候自动的恢复(只有在为该UI提供了唯一ID后才起作用);
若需复写该方法从而存储额外的状态信息时,应先调用父类的onSaveInstanceState()(因为默认的onSaveInstanceState()帮助UI存储它的状态);
只使用该方法记录Activity的瞬间状态(UI的状态),而不是去存储持久化数据,因为onSaveInstanceState()调用时机不确定性;可使用 onPause()[一定会执行]存储持久化数据;
Activity提供了onRestoreInstanceState()方法,该方法是Activity在重新创建后恢复之前保存状态的核心方法。
若被动关闭了Activity,即调用了onSaveInstanceState(),那么下次启动时会调用onRestoreInstanceState()。
onCreate()--->onStart()--->onRestoreInstanceState()--->onResume()
注意: onSaveInstanceState()、onRestoreInstanceState()不一定 成对被调用
如:当正在显示Activity A时,用户按下HOME键回到主界面,然后用户紧接着又返回到Activity A,此时Activity A一般不会因为内存的原因被系统销毁,故Activity A的onRestoreInstanceState()不会被执行;
针对以上情况,onSaveInstanceState保持的参数可以选择在onCreate()内部进行解析使用,因为onSaveInstanceState的bundle参数会传递到onCreate方法中,可选择在onCreate()中做数据还原。
至此:Activity的启动模式及Activity的状态保持及恢复介绍完毕。