Android开发渠道是敞开的渠道,而坐落四层结构顶端的运用开发,必定涉及到Android组件。本文将为咱们详细介绍Android组件。
组件(Component),在谈及所谓架构和重用的时分,是一个重要的作业。许多时分都会说依据组件的软件架构,指的是希望把程序做乐高似的,有一堆接口规范封装完好的组件放在哪里,想用的时分取上几个一调配,整个程序就构建完结了。
在开篇的时分就在说,Android是一个为组件化而建立的渠道,它引进所谓Mash-Up的概念,这使得你在运用的最上层,想做的不组件化都是很困难的一件作业(底层逻辑,好吧,管不了…)。详细说来,Android有四大组件四喜丸子:Activity、Service、Broadcast Receiver、Content Provider。
Activity
做一个完好的Android程序,不想用到Activity,真的是比较困难的一件作业,除非是想做绿叶想疯了。由于Activity是Android程序与用户交互的窗口,在我看来,从这个层面的视角来看,Android的Activity特像网站的页面。
首要,一个网站,假如一张页面都没有,那…,真是一颗奇葩。而一张页面往往都有个独立的主题和功用点,比方登录页面,注册页面,办理页面,如是。
在每个页面里边,会放一些链接,已完结功用点的串联,有的链接点了,刷,跑到同一站点的另一个页面去了;有的链接点了,啾,或许跳到其他网站的页面去;还有的链接点了,恩…,这次没跑,但当时页面的姿态或许有所改变了。这些方法,和Activity给人的感觉很像,只不过完结战略不同算了,究竟Android这套架构的中心思维,自身就来自源于Web的Mash-Up概念,视为页面的客户端化,也未尝不可。
Activity,在四大组件中,无疑是最杂乱的,这年头,相同东西和界面挂上了勾,都简化不了,想一想,独立做一个运用有多少时刻沦落在了界面上,就能揣摩清楚了。从视觉效果来看,一个Activity占有当时的窗口,呼应全部窗口作业,具有有控件,菜单等界面元素。从内部逻辑来看,Activity需求为了坚持各个界面情况,需求做许多耐久化的作业,还需求妥善办理生命周期,和一些转跳逻辑。关于开发者而言,就需求派生一个Activity的子类,然后埋头苦干上述作业。关于Activity的更多细节,先能够拜见:reference/android/app/Activity.html。后续,会献上更为翔实的分析。
Service
服务,从最直白的视角来看,便是剥离了界面的Activity,它们在许多Android的概念方面比较挨近,都是封装有一个完好的功用逻辑完结,只不过Service不抛头露脸,仅仅默默无声的做坚实的后台。
但其实,换个视点来看,Android中的服务,和咱们一般说的Windows服务,Web的后台服务又有一些附近,它们一般都是后台长时刻运转,承受上层指令,完结相关业务的模块。用运转方法来看,Activity是跳,从一个跳到一个,呃…,这有点像模态对话框(或许还像web页面好了…),给一个输入(抑或没有…),然后不管不顾的让它运转,脱离时回来输出(同抑或没有…)。
而Service不是,它是等,等着上层连接上它,然后发生一段耐久而纠缠的通讯,这就像一个用了Ajax页面,看着没啥改变,鬼鬼祟祟的和Service不知暗送秋波多少回了。
但和一般的Service仍是有所不同,Android的Service和全部四大组件相同,其进程模型都是能够装备的,调用方和发布方都能够有权力来挑选是把这个组件运转在同一个进程下,仍是不同的进程下。这句话,能够拿把指甲刀刻进脑际中去,它凸显了Android的运转特征。假如一个Service,是有希望运转在于调用方不同进程的时分,就需求运用Android供给的RPC机制,为其布置一套进程间通讯的战略。
Android的RPC完结,如上图所示(好吧,也是从SDK中拿来主义的…),无甚稀罕,依据署理方法的一个完结,在调用端和服务端都去生成一个署理类,做一些序列化和反序列化的作业,使得调用端和服务器端都能够像调用一个本地接口相同运用RPC接口。
Android中用来做数据序列化的类是Parcel,拜见:/reference/android/os/Parcel.html,封装了序列化的细节,向外供给了满足目标化的拜访接口,Android声称完结十分高效。
还有便是AIDL (Android Interface Definition Language) ,一种接口界说的言语,服务的RPC接口,能够用AIDL来描绘,这样,ADT就能够协助你主动生成一整套的署理方法需求用到的类,都是想起来很乏力写起来很苦力的那种。更多内容,能够再看看:guide/developing/tools/aidl.html,假如有兴致,能够找些其他PRC完结的材料lou几眼。
关于Service的完结,还强推参看API Demos这个Sample里边的RemoteService完结。它完好的展现了完结一个Service需求做的作业:那便是界说好需求承受的Intent,供给同步或异步的接口,在上层绑定了它后,经过这些接口(许多时分都是RPC的…)进行通讯。在RPC接口中运用的数据、回调接口目标,假如不是规范的体系完结(体系可序列化的),则需求自界说aidl,全部全部,在这个Sample里都有表达,强荐。
Service从完结视点看,最特别的便是这些RPC的完结了,其他内容,都会挨近于Activity的一些完结,或许不再见胪陈了。
Broadcast Receiver
在实践运用中,咱们常需求等,等候体系抑或其他运用宣布一道指令,为自己的运用擦亮明灯指明方向。而这种等候,在许多的渠道上,都会需求支付不小的价值。
比方,在Symbian中,你要等候一个来电音讯,显现归属地之类的,有必要让自己的运用委曲求全鬼鬼祟祟的开机发动,消隐图标躲藏使命项,埋伏在后台,监控着相关作业,等候转瞬即逝的出手机遇。这是一件很发指的作业,不光白白耗费了体系资源,还留了个流氓软件的臭名,这真是卖力不巴结的正面典型。
在Android中,充分考虑了广泛的这类需求,所以就有了Broadcast Receiver这样的一个组件。每个Broadcast Receiver都能够接纳一种或若干种Intent作为触发作业(有不知道Intent的么,后边会知道了…),当发生这样作业的时分,体系会担任唤醒或传递音讯到该Broadcast Receiver,任其处置。在此之前和这今后,Broadcast Receiver是否在运转都变得不重要了,及其绿色环保。
这个完结机制,显然是依据一种注册方法的,Broadcast Receiver将其特征描绘并注册在体系中,依据注册机遇,能够分为两类,被我冠名为冷热插拔。所谓冷插拔,便是Broadcast Receiver的相关信息写在装备文件中(求装备文件概况?稍安,后续奉上…),体系会担任在相关作业发生的时分及时告诉到该Broadcast Receiver,这种方法适合于这样的场景。某作业方法 -> 告诉Broadcast -> 发动相关处理运用。比方,监听来电、邮件、短信之类的,都隶属于这种方法。而热插拔,望文生义,插拔这样的作业,都是由运用自己来处理的,一般是在OnResume作业中经过registerReceiver进行注册,在OnPause等作业中反注册,经过这种方法使其能够在运转期间坚持对相关作业的重视。比方,一款优异的词典软件(比方,有道词典…),或许会有在运转期间重视网络情况改变的需求,使其能够在有廉价网络的时分优先运用网络查询词汇,在其他情况下,首要经过本地词库来查词,然后统筹腰包和体会,两全其美一举两得两全其美(注,实在在有道词典中有这样的才干,但不是经过Broadcast Receiver完结的,仅认为例…)。而这样的监听,只需求在其作业情况下坚持就好,不运转的时分,管你是天大的网路改变,与我何干。其方法能够归结为:发动运用 -> 监听作业 -> 发生时进行处理。
除了承受音讯的一方有多种方法,发送者也有很重要的挑选权。一般,发送这有两类,一个便是体系自身,咱们称之为体系Broadcast音讯,在reference/android/content/Intent.html的Standard Broadcast Actions,能够求到相关音讯的概况。除了体系,自界说的运用能够放出Broadcast音讯,经过的接口能够是Context.sendBroadcast,抑或是Context.sendOrderedBroadcast。前者宣布的称为Normal broadcast,全部重视该音讯的Receiver,都有机遇取得并进行处理;后者放出的称作Ordered broadcasts,望文生义,承受者需求按资排辈,排在后边的只能吃前面吃剩余的,前面的心境欠好私吞了,后边的只能喝西北风了。
当Broadcast Receiver接纳到相关的音讯,它们一般做一些简略的处理,然后转化称为一条Notification,一次振铃,一次轰动,抑或是发动一个Activity进行进一步的交互和处理。所以,尽管Broadcast整个逻辑不杂乱,却是满足有用和好用,它一致了Android的作业播送模型,让许多渠道都相形见绌了。更多Broadcast Receiver相关内容,拜见:/reference/android/content/BroadcastReceiver.html。
Content Provider
Content Provider,听着就和数据相关,没错,这便是Android供给的第三方运用数据的拜访计划。在Android中,对数据的维护是很紧密的,除了放在SD卡中的数据,一个运用所持有的数据库、文件、等等内容,都是不允许其他直接拜访的,但有时分,交流是必要的,不只对第三方很重要,对运用自己也很重要。
比方,一个联络人办理的运用。假如不允许第三方的运用对其联络人数据库进行增删该查,整个运用就失去了可扩展力,必将被其他运用扔掉,然后另立门户,自个玩自个的去了。
Andorid当然不会真的把每个运用都做成一座孤岛,它为全部运用都预备了一扇窗,这便是Content Provider。运用想对外供给的数据,能够经过派生ContentProvider类,封装成一枚Content Provider,每个Content Provider都用一个uri作为独立的标识,形如:content://com.xxxxx。全部东西看着像REST的姿态,但实践上,它比REST更为灵敏。和REST相似,uri也能够有两种类型,一种是带id的,另一种是列表的,但完结者不需求依照这个方法来做,给你id的uri你也能够回来列表类型的数据,只需调用者理解,就不妨,不用苛求所谓的REST。
别的,Content Provider不好REST相同只要uri可用,还能够承受Projection,Selection,OrderBy等参数,这样,就能够像数据库那样进行投影,挑选和排序。查询到的成果,以Cursor(拜见:reference/android/database/Cursor.html )的方法进行回来,调用者能够移动Cursor来拜访各列的数据。
Content Provider屏蔽了内部数据的存储细节,向外供给了上述一致的接口模型,这样的笼统层次,大大简化了上层运用的书写,也对数据的整合供给了更便利的途径。Content Provider内部,常用数据库来完结,Android供给了强壮的Sqlite支撑,但许多时分,你也能够封装文件或其他混合的数据。
在Android中,ContentResolver是用来建议Content Provider的定位和拜访的。不过它仅供给了同步拜访的Content Provider的接口。但一般,Content Provider需求拜访的或许是数据库等大数据源,功率上不满足快,会导致调用线程的拥塞。因而Android供给了一个AsyncQueryHandler(拜见:reference/android/content/AsyncQueryHandler.html),协助进行异步拜访Content Provider。
在各大组件中,Service和Content Provider都是那种需求继续拜访的。Service假如是一个耗时的场景,往往会供给异步拜访的接口,而Content Provider不管功率怎样,都供给的是约好的同步拜访接口。我想这遵从的便是场景导向规划的准则,由于Content Provider仅是供给数据拜访的,它不能坚信详细的运用场景怎样,会怎样运用它的数据;而相比之下,Service包括的逻辑更杂乱更完好,能够选择大部分时分运用某接口的场景,然后确认最恰当的接口是同步仍是异步,简化了上层调用的逻辑。
装备
四大组件说完了,四大组件暗地的英豪也该进场了,那便是每个运用都会有一份的装备文件,称号是AndroidManifest.xml,在工程的根目录下。在这个装备文件中,不只会描绘一些运用相关的信息,很重要的,会包括一个运用中全部组件的信息。假如你派生Activity或许Service完结了一个相关的类,这仅仅把它组件化的第一步,你需求把这个类的相关信息写到装备文件中,它才会作为一个组件被运用到,不然只能默默无闻的暗淡度过余生。
摆了一幅图出来,这次不是偷来的,是敝帚自珍原创,所以没有意外的画的很丑,但根本仍是能够体现出一些意思。在In Others的部分,这里是一般渠道运用之间通讯和交互的模型,每个运用都有很激烈的运用鸿沟(往往表现为进程鸿沟…),App 1的仍是App 2的,分得很是清楚。每个运用内部,都有自己的逻辑去切分功用组件,这样的切分一般没有什么规范,率性而为。运用间的交互逻辑也比较零星,App 1与App 2交互,往往需求清晰知道对方运用的详细信息,比方进程ID,进程称号之类的,这样使得运用和运用之间的联络,变得很僵硬。而上层运用和体系运用的通讯,往往有许多特定的方法,这种方法,很或许是无法直接运用在一般运用之间的,换而言之,体系运用是有必定特别性的。
要点,在图的下半部,描绘的是Android的运用现象。在Android中,运用的鸿沟,在组件这个层面,是极度含糊,什么进程、什么运用,都能够不用感知到。举个比方,App 1,完结了A和B两个组件,App 2,完结了C这个组件。A和C,都想运用B这个组件,那么它们的运用方法是完全一致的,都需求经过体系中心的组件辨认和通讯机制,找到和运用组件B。A,虽说和B是一个娘胎里蹦出来的,很欠好意思,没有任何特别的后边和捷径,仍是要跑规则的途径才干用到,一片和谐社会的现象情不自禁。
在Android中,全部组件的辨认和音讯传递逻辑都有必要依靠底层中心来进行(通讯能够没有底层中心的参加,比方一旦Service找到了,就能够和它发生耐久的通讯…),没有底层中心的穿针引线,任何两个组件都无法发生联络。比方一个Activity,跳到另一个Activity,有必要要向底层中心建议一个Intent,有底层解析并认可后,会找到另一个Activity,把相关音讯和数据传给它。一个Activity想运用Content Provider中的数据,有必要经过底层中心解析相关的uri,定位到这个Content Provider,把参数传递给它,然后回来Activity需求的Cursor。这样的规划,确保了底层中心对全部组件的肯定掌控权和认知权,使得搭积木似的开发变成或许。
为了,使得中心体系能够完好的掌握每个组件的信息,这就需求装备文件了。装备文件,便是将组件插到底层中心上的这个插头。只要经过这个插头插在底层中心的插座上(不要乱想,非十八禁…),组件才干够发光发热,闪烁光辉。
组件的装备信息在我看来首要包括两个方面,一部分是描绘怎样认知。比方,Activity、Service、Broadcast Receiver都会有姓名信息,和希望能够掌握的Intent信息(权且当作音讯好了…),Content Provider会有一个描绘其身份的uri。当其他组件经过这样的姓名或许Intent,就能够找到它。
另一部分是运转相关的信息。这个组件,希望怎样来运转,放在独自的进程,仍是和调用者一个进程,仍是找相关的其他组件挤在同一个进程里边,这些内容,都能够在装备的时分来决议(调用者在这个束缚范围内,有进一步的挑选权…)。更多装备项,请拜见:guide/topics/manifest/manifest-intro.html。
经过前续内容,或许能够协助咱们对Android组件有个初略的了解。但这些了解都还停留在静态层面,程序是个动态的概念,关于各个组件详细是怎样联络在一起的,怎样手拉手运转起来完结一项功用的,这便是后话了。
发布者:博子