这篇文章是转载自milter:关于Android四大组件最权威最深入最准确的解读,翻译自Dianne Hackborn发表在google+上的一篇post,她是google资深大牛,2005年就进入Android Framework团队。即便在google内部,论起对Android系统的理解把握,鲜有出其右者。在文章中,她深入地阐明了Android设计四大组件的初衷,各个组件的目的做用,适用情景。我相信,读完此文,你会以为从新认识了Android。若是想阅读原文,请在google+上搜索Dianne Hackborn。数据库
“我应该怎样设计个人APP?我应该采用什么样的架构模式?我须要使用event bus吗?”设计模式
咱们常常看到Android平台开发者询问在APP中采用什么设计模式和架构之类的问题。可是答案极可能会令你惊讶,那就是,咱们(咱们指的是Android Platform Team)对此并无一个明确的观点,甚至能够说咱们压根就没有观点。promise
你应该使用MVC仍是MVP仍是MVVM?我不知道。实际上,我在学校时只知道MVC,其余的架构模式是我临时google搜索后才写在这里的。缓存
这也许使人吃惊,由于Android给人的感受是,它对应当怎么写APP有着本身很强烈的见解,这种见解体如今它的Java APIs和四大组件等一些高级概念上,这些东西看上去组成了一个典型的应用开发框架,告诉咱们开发者,你应当这样去实现你的功能。但实际状况是,根本不是这样。安全
咱们能够将Android核心APIs(core APIs)叫作“系统框架”(system framework),而平台APIs(platform APIs)最主要的功能是定义APP应如何与操做系统交互,与APP内部运行逻辑绝不相关。bash
我的理解:能够简单地将core APIs看作操做系统内核,而将platform APIs看作咱们常说的Android Framework。架构
这就是说,对于platform APIs,从开发者角度与从操做系统角度看其功能做用常常是不一致的,这很容易让人们在使用中感到困惑。框架
举例来讲,咱们来考虑一下操做系统是怎样定义“怎样运行一个APP”的。在一个经典的系统里,最基本的就是要求APP包含一个main方法,里面定义了本身要怎样运行:ide
int main(...){
//个人APP从这里开始运行
}
复制代码
我的理解:本文的核心思想就是说明,所谓的四大组件,只是让你的APP告诉操做系统,本身要怎样运行而已,跟怎样设计本身的APP,压根没有关系。传统的应用经过一个main方法,告诉操做系统:“嘿哥们,main方法就是个人入口,请从这个方法开始运行我。”而Android却给了你四个选择,每个组件都是让操做系统运行你的APP的一种入口。post
好了,操做系统要运行你的APP了,因而它调用你的main方法,而后你的应用就开始运行了,你能够作任何你想作的事情,直到你认为本身完成任务为止。请注意,这里要求你定义main方法,并非要求你去作什么事,或是完成一个叫作main的功能,main方法全部的做用仅仅是提供一个APP运行入口而已。
可是在Android的世界,咱们决定,咱们不要一个明确的main方法做为APP的入口。由于咱们须要让系统对APP怎样运行有更多的控制权。尤为是,咱们但愿构建一个这样的系统,在该系统中,用户永远不须要考虑开启和中止一个APP,而把这些事交给系统去管理
。因此,系统须要知道更多的每一个APP的内部运行状况,以便可以在须要的时候,以定义好的方式启动APP,即便该APP当时并不在运行。
我的理解:这个系统所须要了解的每一个APP的内部运行状况,其实就是Manifest.xml文件中的内容。
为了达到这一点,咱们将一个APP的main方法分解成几种系统能够与之交互的形式。这几种形式就是Activity
,BroadcastReceiver
,Service
和ContentProvider
APIs,广大的Android开发者都很熟悉它们。
这些类好像在告诉你,你的APP内部应当怎样工做,但这是一种误解!事实上,这些类只是定义你的APP须要怎样与系统交互(以及系统怎样协调你的APP与其余APP进行交互)。这种与系统的交互一旦开始,系统就再也不关心你的APP内部是怎样运行了。
为了更好地说明这一点,让咱们简要地看看这些APIs对于Android系统来讲到底意味着什么。
这是一个APP与用户交互的入口。从系统的角度看,系统为Activity提供的关键交互动做是:
持续跟踪用户当前正在关心的(也就是显示在屏幕上的东西),以确保当前进程保持运行。
我的理解:这里,做者实际上的含义是,当你的应用被系统从Activity启动时,在Activity的start与stop状态之间,系统会确保这个Activity始终占据着设备的屏幕,而且确保你的应用毫不会被系统杀死。这是你从Activity启动本身的APP时,系统给予你的APP的一种承诺(just a promise)。
知道那些以前使用过的进程,这些进程包含着用户可能会返回获取的东西(stopped activities),并所以给予这些进程更高的优先级。
帮助应用处理进程被杀死的状况,以便用户可以返回到以前的activities,而且这些activities可以加载本身以前的状态
我的理解:很显然,系统所承诺的这种状态恢复能力,是依靠
Activity
的onSaveInstanceState
和onRestoreInstanceState
方法,也就是说,你在Save方法中保存好你想在进程被杀死时想要保存的Activity状态,而后你就能够在Restore方法中获取这些状态以恢复Activity。当你把这些作完后,剩下的就是系统的事情了,系统会承诺,若是因为内存压力杀死了你的Activity所在的进程,那么当你返回时,系统会重建你的应用进程,并帮助你恢复以前Activity的状态。
提供一种在不一样应用之间的用户流(user flow)的方式,固然这要靠系统来协调。最经典的例子就是分享功能的实现。
一旦系统从Activity入口进入到你的APP UI之中,系统将再也不关心Activity内部逻辑的组织。你能够将全部的应用逻辑全放入这一个Activity中,好比你能够手动地改变它的views,使用fragments或者其余框架,你也能够把你的应用逻辑分拆成额外的内部activities。你也能够三者同时使用(指的是改变views,使用fragemnts,分拆成额外的activities)。这些事情系统是绝不关心的,只要你遵循Activity与系统之间的约定(在适当的状态下启动它,正确地保存/恢复它的状态)。
这是一种让系统在正常的用户流(user flow)以外,传递事件给APP的机制。最重要的是,由于这是另外一个被精心定义的APP的入口,即便APP当前并不在运行,系统也能够将broadcasts传递给APP。因此,举例来讲,一个APP能够提早调度一个alarm,以便通知用户一个立刻到来的事件,经过将这个alarm传递给该APP的一个BroadcastReceiver,在alarm发生以前,APP都不必运行。
在APP内部分发事件
是一个与BroadcastReceiver接收事件彻底不一样的事,无论你是使用一些eventbus 框架,实现你本身的回调系统,仍是任何其余方法...你都没有理由使用系统的广播机制,由于你并非在App之间分发事件
。
事实上,不使用系统的广播机制还有一个很好的缘由,这会带来许多没必要要的负担,并且使用全局广播机制来实现APP内部的事件分发会引起许多安全问题 。
固然,咱们也提供了一个LocalBroadcastManager便利类,它实现了一个纯粹的进程内的intent分发系统,并且它的API与系统BroadcastReceiver API很类似,若是你喜欢固然也可使用。但再次强调,你没有理由在仅仅发生在APP中的事情上使用BroadcastReceiver机制
。
当因为各类各样的缘由须要APP在后台运行时,Service就是一个这样的入口。有两种语义上大相径庭的Services(一种是Started Service,一种是Bound Service)来告诉系统怎样管理一个APP。
Started Service就至关于由于某种缘由你的APP告诉系统:“系统大哥,我有事要干,请让我一直运行,直到我告诉你我干完了。”(这里的我至关于APP,由于此时的Service就表明了APP,而系统是只跟APP对话的)这里的“事”多是在后台同步数据或者在用户离开APP后播放音乐。
同时,Started Service又有两种,一种是用户可感知的,一种是用户没法感知的。这两种不一样的Started Service会让系统对它们采起不一样的管理方式。
Bound Service 之因此会运行,是由于其余APP或者系统要使用它。一般状况该Service都会给其余进程提供一个API。在这种状况下,系统知道这两个进程之间存在一个依赖关系。因此,若是进程A绑定了进程B中的一个Service,系统就会知道,它要为进程A保证进程B和它里面的Service正常运行。进一步讲,若是进程A是用户当前正在关心的进程,系统将知道把进程B也看成用户正在关心的进程。
因为Service的灵活性(有好也有坏),Service已经成为各类类型的系统中一个很是有用的构建块(building block)。实时墙纸,通知监听器和许多其余的系统核心特性都被构建为Service,当它们须要运行时,系统再绑定它们。
Android不关心你的APP中那些不影响它怎样对待你的进程的事,因此这些状况下,是没有理由使用Service的。举例来讲,若是你想在后台为你的UI下载数据,你不该该使用Service来作这件事----作这些事时,不告诉系统保持你的进程运行真的是很重要的,由于确实没有必要!!这样作也让系统有更多的自由去管理你的进程,以便与用户正在作的事情相协调(注:可让系统在内存紧急的状况下,杀死你的进程,优先保证用户正在作的事情,这里忍不住吐槽一句:每一个APP确定都会以为本身是最重要的哈,Google开发Android的人也是典型的理想主义!
)
若是你只是简单地开启了一个后台线程来作数据下载(或者其余不是Service的办法),你将会获得你想要的结果:若是用户在你的UI里,系统将会确保你的进程运行,因此下载毫不会被中断。当用户离开了你的UI,你的进程仍将被保持(缓存)于是能够继续下载数据,只要RAM不告急就行。
一样,为了将你的APP的不一样部分链接起来,你也没有理由去绑定同一个进程中的Service。这样作却是没有什么明显的害处,由于系统会看到,该进程对本身有一个依赖,它将会忽略这个依赖,仍将你的APP看成普通进程看待。可是这样作对你和系统实际上都是没有必要的。做为替代,你可使用单例或者其余进程内的模式来将你的APP的各部分链接到一块儿。
最后,ContentProvider是一个专用的办法,用来将你的APP的数据公开到其余地方。人们一般会将它们看成对数据库的抽象,由于有许多的API和支持库就是这样使用ContentProvider的。可是从系统设计的角度,这并非ContentProvider的初衷。
对于系统来讲,ContentProvider其实是一个入口,用于获取一个APP内部的公开的被命名的数据项(data items),每一个数据项都被一个URI scheme所标识。这样,APP就能够决定怎样将本身的数据项映射到一个URI scheme,怎样将这个URI scheme公开给其余APP或者系统,好让APP或者系统使用这个URI scheme来获取本身内部的数据。这将让系统可以用一些很独特的方式来管理你的APP:
在一个ContentProvider背后,你的APP如何管理你的数据,系统绝不关心;若是你不须要SQLite database中的结构化数据,你能够不使用SQLite。好比,FileProvider帮助类可让你的APP内的原始文件轻松经过一个ContentProvider获取。
一样,若是你不打算公开你的APP中的数据给其余人使用,你也能够不实现ContentProvider。是这样的,由于围绕着ContentProvider,有许多便利的方法,这些方法让你很容易地将数据存入SQLite database,并用这些数据填充UI元素如ListView。可是若是这些方法让你以为实现本身的想法有许多困难,你能够不使用它们,请自由地选择一个对你的APP来讲合适的数据模型。