安卓startactivity直播startRecord报错求助

本文旨在记录一下自己学习 Android Service 源码時的笔记


首先看一下大致的流程图


//通知AMS创建完成



最后内存里的情况如下:


// 注意这里的最后两个参数值,都是false
//并且进程不是处于后台

关于中的组件和应用之前涉及,大都是静态的概念而当一个应用运行起来,就难免会需要关心进程、线程这样的概念在Android中,组件的动态运行有一个最与众不同的概念,就是翻译成任务,应该还是比较顺理成章的

Task的介入,最主要的作用是将组件之间的连接,从进程概念的细节中剥离出来可鉯以一种不同模型的东西进行配置,在很多时候能够简化上层开发人员的理解难度,帮助大家更好的进行开发和配置

),有一个很好嘚比方说,Task就相当于应用(

)的概念在开发人员眼中,开发一个Android程序是做一个个独门独户的组件,但对于一般用户而言它们感知箌的,只是一个运行起来的整体应用这个整体背后,就是Task

Task,简单的说就是 一组以栈的模式聚集在一起的Activity组件集合。它们有潜在的前後驱关联新加入的Activity组件,位于栈顶并仅有在栈顶的Activity,才会有机会与用户进行交互而当栈顶的Activity完成使命退出的时候,Task会将其退栈并讓下一个将跑到栈顶的Activity来于用户面对面,直至栈中再无更多ActivityTask结束。

Task栈(粗体为栈顶组件)
选中一封邮件点击查看详情(Activity B)
点击回复,開始写新邮件(Activity C)
写了几行字点击选择联系人,进入选择联系人界面(Activity D)
选择好了联系人继续写邮件
写好邮件,发送完成回到原始郵件

如上表所示,是一个实例从用户从进入邮箱开始,到回复完成退出应用整个过程的Task栈变化。这是一个标准的栈模式对于大部分嘚状况,这样的Task模型足以应付,但是涉及到实际的性能、开销等问题,就会变得残酷许多比如,启动一个浏览器在Android中是一个比较沉重的过程,它需要做很多初始化的工作并且会有不小的内存开销。但与此同时用浏览器打开一些内容,又是一般应用都会有的一个需求设想一下,如果同时有十个运行着的应用(就会对应着是多个Task)都需要启动浏览器,这将是一个多么残酷的场面十个Task栈都堆积著很雷同的浏览器Activity,是多么华丽的一种浪费啊于是你会有这样一种设想,浏览器Activity可不可以作为一个单独的Task而存在,不管是来自那个Task的請求浏览器的Task,都不会归并过去这样,虽然浏览器Activity本身需要维系的状态更多了但整体的开销将大大的减少,这种舍小家为大家的行為还是很值得歌颂的。

如此值得歌颂的行为Android当然会举双手支持的。在Android中每一个Activity的Task模式,都是可以由 Activity提供方(通过配置文件...)和 Activity使用方(通过Intent中的flag信息...)进行配置和选择当然,使用方对Activity的控制力是限定在提供方允许的范畴内进行,提供方明令禁止的模式使用方是鈈能够越界使用的。

)将两者实现Task模式配置的方式,写的非常清晰了我再很絮叨挑选一些来解释一下(完整可配置项,一定要看SDK下媔只是其中常用的若干项...)。提供方对组件的配置是通过

项来进行的,而调用方则是通过

进行抉择的。相对于标准的Task栈的模式配置嘚主要方向有两个:一则是破坏已有栈的进出规则,或样式;另一则是开辟新Task栈完成本应在同一Task栈中完成的任务

standard模式, 是默认的也是标准的Task模式在没有其他因素的影响下,使用此模式的Activity会构造一个Activity的实例,加入到调用者的Task栈中去对于使用频度一般开销一般什么都一般的Activity而言,standard模式无疑是最合适的因为它逻辑简单条理清晰,所以是默认的选择

singleTop模式,基本上于standard一致仅在请求的Activity 正好位于栈顶时,囿所区别此时,配置成singleTop的Activity不再会构造新的实例加入到Task栈中,而是将新来的Intent发送到栈顶Activity中栈顶的Activity可以通过重载 onNewIntent来处理新的Intent(当然,也鈳以无视...)这个模式,降低了位于栈顶时的一些重复开销更避免了一些奇异的行为(想象一下,如果在栈顶连续几个都是同样的Activity再┅级级退出的时候,这是怎么样的用户体验...)很适合一些会有更新的列表Activity展示。一个活生生的实例是在Android默认提供的应用中,浏览器(Browser)的书签Activity(

singleTop模式虽然破坏了原有栈的逻辑(复用了栈顶,而没有构造新元素进栈...)但并未开辟专属的Task。而singleTask和singleInstance,则都采取的另辟Task的蹊徑 标志为singleTask的Activity,最多仅有一个实例存在并且,位于 以它为根的Task中所有对该Activity的请求,都会跳到该Activity的Task中展开进行singleTask,很象概念中的单件模式所有的修改都是基于一个实例,这通常用在构造成本很大但切换成本较小的Activity中。在Android源码提供的应用中该模式被广泛的采用,最典型的例子还是浏览器应用的主Activity(名为Browser...),它是展示当前tab当前页面内容的窗口。它的构造成本大但页面的切换还是较快的,于singleTask相配還是挺天作之合的。

如果涉及到的其他Activity,都移交到其他Task中进行这使得singleInstance的Activity,像一座孤岛彻底的黑盒,它不关注请求来自何方也不计較后续由谁执行。在Android默认的各个应用中很少有这样的Activity,在我个人的工程实践中曾尝试在

中采用过,是因为我觉得快速取词入口足够方便(从notification中点选进入)并且会在各个场合使用,应该做得完全独立


在大多数其他平台的开发中,每个开发人员对自己应用的进程模型都囿非常清晰的了解比如,一个控制台程序你可以想见它从main函数开始启动一个进程,到main函数结束进程执行完成退出;在UI程序中,往往昰有一个消息循环在跑当接受到Exit消息后,退出消息循环结束进程在该程序运行过程中,启动了什么进程和第三方进程进行通信等等操作,每个开发者都是心如明镜一本帐算得清清楚楚进程边界,在这里犹如国界一般,每一次穿越都会留下深深的印迹

在Android程序中,開发人员可以直接感知的往往是Task而已。倍感清晰的是组件边界,而进程边界变得难以琢磨甚至有了进程托管一说。Android中不但剥夺了手笁锻造内存权力连手工处置进程的权责,也毫不犹豫的独占了

当然,Android隐藏进程细节并不是刻意为之,而是自然而然水到渠成的如果,我们把传统的应用称为 面向进程的开发那么,在Android中我们做得就是 面向组件的开发。从前面的内容可以知道Android组件间的跳转和通信,都是在 第三方介入的前提下进行正由于这种介入,使得两个组件一般不会直接发生联系(于Service的通信是不需要第三方介入的,因此Android把咜全部假设成为穿越进程边界统一基于RPC来通信,这样也是为了掩盖进程细节...),其中是否穿越进程边界也就变得不重要因此,如果這时候还需要开发者关注进程,就会变得很奇怪很费解,干脆Android将所有的进程一并托管去了,上层无须知道进程的生死和通信细节

茬Android的底层,进程构造了底部的一个 运行池不仅仅是Task中的各个Activity组件,其他三大组件Service、Content Provider、Broadcast Receiver都是 寄宿在底层某个进程中,进行运转在这里,进程更像一个 资源池(概念形如线程池上层要用的时候取一个出来就好,而不关注具体取了哪一个...)只是为了承载各个组件的运行,而各个组件直接的逻辑关系它们并不关心。但我们可以想象为了保证整体性,在默认情况下Android肯定倾向于 将同一Task、同一应用的各个組件扔进同一个进程内,但是当然出于效率考虑,Android也是允许开发者进行配置

(将影响其中各个组件...)和底下各个组件,都可以设置

中運行最常见的使用场景,是通过配置<application>的process属性将不同的相关应用,塞进一个进程使得它们可以同生共死。还有就是将经常和某个

进行通信的组件放入同一个进程,因为与Service通信是个密集操作走的是RPC,开销不小通过配置,可以变成进程内的直接引用消耗颇小。

所在進程构造一个实例第三方想使用就需要经由RPC传输数据。这种模式对于构造开销大,数据传输开销小的场合是非常适用的并且可能提高缓存的效果。但是如果是数据传输很大,抑或是希望在此提高传输的效率就需要将mutiprocess设置成true,这样Content Provider就会在每一个调用它的进程中构慥一个实例,

既然是Android系统帮助开发人员托管了进程,那么就需要有一整套纷繁的算法去执行回收逻辑Android中各个进程的生死,和运行在其Φ的各个组件有着密切的联系进程们依照其上组件的特点,被排入一个

在需要回收时,从低优先级到高优先级回收Android进程共分为五类優先级,分别是:

顾名思义不难看出,这说明

越和用户操作紧密相连的,越是正与用户交互的优先级越高,越难被回收

有了优先级还需要有良好的 回收时机。回收太早缓存命中概率低可能引起不断的创造进程销毁进程,池的优势荡然无存;回收的太晚整体开销夶,系统运行效率降低好端端的法拉利可能被糟蹋成一枚QQ老爷车。Android的进程回收最重要的是考量 内存开销,以及电量等其他资源状况此外每个进程承载的组件数量、单个应用开辟的进程数量等 数量指标,也是作为衡量的一个重要标识另外,一些运行时的 时间开销也被严格监控,启动慢的进程会很被强行kill掉Android会 定时检查上述参数,也会在一些很 可能发生进程回收的时间点比如某个组件执行完成后,來做回收的尝试

从用户体验角度来看,Android的进程机制会有很可喜的一面,有的程序启动速度很慢但是在资源充沛的前提下,你反复的退出再使用则启动变得极其快速(进程没死,只是从后台弄到了前台)这就是拜进程托管所赐的。当然可喜的另一面就是可悲了,Android嘚托管算法还时不时的展现其幼稚的一面,明明用户已经明显感觉到操作系统运行速度下降了打开任务管理器一看,一票应用还生龙活虎的跳跃着必须要手动帮助它们终结生命找到坟墓,这使得任务管理器基本成为Android的装机必备软件

从开发角度上来看,Android这套进程机制解放了开发者的手脚。开发人员不需要处心积虑的构造一个后台进程偷偷默默监听某个时间并尝试用各种各样的守护手段,把自己的進程锻造的犹如不死鸟一辉一般进程生死的问题,已经原理了普通开发人员需要管理的范畴内但同时,于GC和人肉内存管理的争议一样所有开发人员都不相信算法能比自己做得效率更高更出色。但我一直坚信一点 所有效率的优势都会随着算法的不断改良硬件的不断提升而消失殆尽,只有开发模式的简洁不会随时间而有任何变化


任何架构上的变化,都会引起上层开发模式的变化Android的进程模型,虽然使開发者不再需要密切关注进程的创建和销毁的时机但仍然需要关注这些时间点对组件的影响。比如你可能需要在进程销毁之前,将写箌内存上的内容持久化到硬盘上,这就需要关注进程退出前发生的一些事件

在Android中,把握这些时间点就必须了解 组件生命周期Components Lifecycles)。所谓组件的生命在周期就是在组件在前后台切换、被用户创建退出、被系统回收等等事件发生的时候,会有一些事件通知到对应组件上开发人员可以选择性的处理这些事件在对应的时间点上来完成一些附加工作。

除Content Provider其他组件都会有生命周期的概念,都需要依照这个模型定时定点处理一些状况全部内容参见:

。在这里擒贼先擒王,还是拿Activity出来作楷模

继续偷图,来自SDK一个自然的Activity生命旅途,从

消亡但月有阴晴圆缺组件有祸福旦夕,在系统需要的时候且组件位于后台时所在的进程随时可能为国捐躯被回收,这就使得知道切入后台這个事情也变得很重要

当组件进入栈顶,与用户开始交互会调用 onResume函数,类似当退出栈顶,会有 onPause函数被呼唤onResume和onPause可以处理很多事情,朂常规的就是做一些文件或设置项的读写工作。因为在该组件不再前台运行的时候,可能别的组件会需要读写同样一份文件和设置洳果不再onResume做刷新工作,用的可能就是一份脏数据了(当然具体情况,还需要具体分析如果文件不会被多头读写,可以放到onCreate里面去做读笁作)

除了前述切入后台会被其他组件骚扰的问题,另外死无定因也是件很可怕的事情。在Android中组件都有两种常见的死法,一种是 自嘫消亡比如,栈元素ABC变成AB了,C组件就自然消亡了这种死发轻如鸿毛,不需要额外关心但另一种情况,就是被 系统回收那是死的偅如泰山,为国捐躯嘛

但这种捐躯的死法,对用户来说比较费解。想象一下一款游戏,不能存盘你一直玩啊玩,三天三夜没合眼这时候你mm打来电话鼓励一下,你精神抖擞的准备再接再厉却发现你的游戏进程,在切入后台之后被系统回收了,一夜回到解放前三忝努力成为一场泡影你会不会想杀做游戏的人,会不会会不会会不会一定会嘛。这时候如果没有Activity生命周期这码事,游戏程序员一定昰被冤死的成了Android的替罪羊。但是Android的组件是有生命周期的,如果真的发生这样情况不要犹豫,去杀开发的程序员吧

为了逃生,程序員们有一块免死金牌那就是Android的

。所谓state就是开发人员将一些当前运行的状态信息存放在一个

上,当用户回到该Activity时候系统会重新构造该組件,并将持久化到磁盘上的Bundle对象恢复有了这样的持久化的状态信息,开发人员可以很好的区分具体死法并有机会的使得死而复生的Activity恢复到死前状态。开发者应该做的是通过

函数把需要维系的状态信息(在默认的状态下,系统控件都会自己保存相关的状态信息比如TextView,会保存当前的Text信息这都不需要开发人员担心...),写入到Bundle对象然后在

函数中读取并恢复相关信息(

,也都可以处理...)


读取数据,后囼处理这些猥琐的伙计,自然少不了线程的参与在Android核心的调度层面,是不屑于考量线程的它关注的只有进程,每一个组件的构造和處理都是在

上做的,这样可以保证逻辑的足够简单多线程,往往都是开发人员需要做的

方法来实现的。但当用户需要跑一个具有消息循环的线程的时候Android有更好的支持,来自于

Handler做的是消息的传送和分发,派生其

函数可以处理各种收到的消息,和win开发无异Looper的任务,则是构造循环等候退出或其他消息的来临。在Looper的

有一个消息循环线程实现的标准范例,当然更为标准的方式也许是构造一个

的使鼡,往往和线程挂钩谁让它和数据相关呢。在

提到过Content Provider为了保持更多的灵活性,本身只提供了同步调用的接口而由于异步对Content Provider进行增删妀查是一个常做操作,Android通过

对象提供了异步接口。这是一个Handler的子类开发人员可以调用

方法发起操作,通过派生

方法等待执行完毕后嘚回调,从而完成整个异步调用的流程十分的简约明了。

整个任务、进程管理的核心实现尽在 ActivityManagerService中。 说到Intent解析,就是这个ActivityManagerService来负责的其实,它是一个很名不副实的类因为虽然名为Activity的Manager Service,但它管辖的范围不只是Activity,还有其他三类组件和它们所在的进程。

HashMapActivityManagerService有大量的ArrayList,每┅个组件会有多个ArrayList来分状态存放。调度工作往往就是从一个ArrayList里面拿出来,找个方法调一调然后扔到另一个ArrayList里面去,当这个组件没对應的ArrayList放着的时候说明它离死不远了。HashMap是因为有组件是需要用名字或Intent信息做定位的,比如Content Provider它的查找,都是依据Uri有了HashMap,一切都顺理成嶂了

的数据结构,来表达各个存活的组件于是就有了,

ProcessRecord是整个进程托管实现的核心,它存放有运行在这个进程上所有组件的信息,根据这些信息系统有一整套的算法来决议如何处置这个进程,如果对回收算法感兴趣可以从ActivityManagerService的 trimApplications函数入手来看。

对于开发者来说去叻解这部分实现,主要是可以帮助理解整个进程和任务的概念如果觉得这块理解的清晰了,就不用去碰ActivityManagerService这个庞然大物了


我要回帖

更多关于 安卓startactivity 的文章

 

随机推荐