应用程序运行原理(Application Fundamentals)
Android 的应用程序是由Java语言编写。应用程序把编译好的Java代码连同数据和资源文件一起被捆绑在Android的一个包中,并用.apk后缀标识。这就是安装应用程序到移动设备上的安装文件,用户下载这些文件到他们的手机上。任何一个.apk文件所包含的所有代码都可以被看作一个应用程序。
在很多情况下,单个的Android应用程序都有其独自的运行空间:
· 默认情况下,所有的应用程序都在其各自的Linux进程中运行。当一个应用程序的代码需要被执行时,Android系统就会去运行这个应用程序所在的进程,而当它不再需要被执行或者系统的资源被其他应用程序占用时,这个进程就会被关闭。
· 每一个进程都拥有其各自的虚拟机,所以任何一个程序代码的运行都独立于其他所有的程序。
· 默认下,任意一个应用程序都被设置了一个唯一标识他们的Linux user ID。应用程序通过控制权限来使程序文件仅仅对用户和应用程序本身可见。不过,也会有方法来把他们导出到其它应用程序中。
可以把两个应用程序设置成共享同一个user ID,在这种情况下,它们就可以互相访问彼此的文件。为了节省系统资源,具有相同ID的应用程序会被安排在同一个Linux进程中以共享同一个虚拟机。
应用程序组件(Application Components)
Android的一个重要特色就在于,一个应用程序可以去调用其它应用程序的资源(在取得这些程序的许可的情况下)。比如,你的程序需要用到一个图片的滚动条,而你又发现有一个应用程序已经开发了一个适合的滚动条,并且这个滚动条对别的应用程序可见,那你就可以调用它的滚动条来代替完成你的开发工作。而你的应用程序并不包含它们的代码,而且也没有和那些程序拼接起来。它只是当有需要的时候启用了其它程序的那部分而已。
为了达到这个目的,当需要一个应用程序的某部分时,系统必须能够去为这个程序开启一个进程并实例化那部分的Java对象。因此,和一般系统的应用程序不同,Android的应用程序并不需要一个唯一的程序入口(比如说不需要main()函数)。当某个部件需要时,程序会有重要的组件使系统来将其实例化并使其运行。
活动(Activities)
activity提供可视化的用户界面,而用户看见的也只能是一个activity。比如,一个activity能提供一个给用户从中选择选项的下拉菜单或者它能够在展示照片时显示照片的标题。一个发送信息的信息文本程序可能拥有一个activity来显示联系人的列表,一个activity来编写信息发送所给要联系人,同时也拥有其它的一些activity来查看历史信息和改变程序的一些设置。虽然他们在同一个用户界面上工作,每个activity彼此独立。任意一个activity都是作为Activity基类的子类在运行。
一个应用程序可能包含一个activity,也可能就像刚刚所提及的信息文本程序一样包含多个activity。到底需要怎样的activity,需要多少个,这问题主要是取决于应用程序和其设计本身。一般情况下,多个activity中,其中一个是作为在运行程序时展现给用户的第一个。而完成从一个activity到另一个activity的运行,是由正在运行的这个activity通过启动下一个activity来实现的。
默认下,每个activity都有一个的窗口。一般来说,这个窗口会充满整个屏幕,不过它也可能会比屏幕小并且会浮现在其它窗口的上面。一个activity也可以利用其它的窗口,比如说,一个要求用户做出回应的弹出对话框显示在activity的最中间,或者当用户选择某个屏幕上的选项时,出现一个对用户展现重要信息的窗口。
窗口的可视容器是由视图类的各个层次提供的,而视图类是一些由View基类派生的子类。每一个可视容器控制一个窗口中的特定矩形控件。父视类容器包含并组织子类的布局设计。叶子视图类(处于视图类的最底层)将在他们所控制的矩形空间里面显示并直接响应用户的命令。因此,视图类是放在用户和程序的交互界面上的。比如,当用户点击一幅小图片时,一个视图可能显示显示这个图片并开始运行某一个动作。Android有好一些已经做好了的视图类可供我们使用,其中包括按钮,文本编辑框,滚动条,菜单,复选框等等。
视图类层次被Activity.setContentView()这个方法置放在一个activity的窗口中。视图容器处于视图类层次的根部。(如果想要了解更多视图和视图类层次的信息,请查阅User Interface文档。)
服务(Services)
服务没有用户界面,它在程序的后台运行,而且其运行时间不能被确定。比如,当用户在关注其它的事情时,可能会有一个服务会在后台播放背景音乐或者从网上下载数据,也可能是在计算一些数据并提供给需要这些数据的activity。每个服务都是由Service基类中派生出来的。
最好的一个例子就是媒体播放器播放其播放列表中的歌曲。播放器可能会有一个或多个activity来使得用户选择并播放曲目。然而,音乐的后台播放并不由activity来管理,因为用户希望自己在做其它事情的时候音乐依然在播放。为了使得音乐继续播放下去,播放器的activity将会启动一个服务来将其放在后台运行。系统会在这个activity退出屏幕之后使音乐在后台服务中继续播放。
我们可以去连接(捆绑)一个正在运行的服务(如果这个服务不是正在运行,那就启动它)。当连接成功时,你可以通过这个服务提供的接口来进行数据传输。对于音乐的后台服务来说,这个接口可能可以使用户去暂停,倒带,停止,和重新播放音乐。
与activity和其它的部件一样,服务在程序进程的主线程中运行。这样他们就不会堵塞别的组件或用户界面的运行,他们经常产生一个新的线程来给这些长时间运行的工作(比如音乐后台播放)。请阅读进程和线程的相关资料。
广播接收器(Broadcast receivers)
广播接收器是一个仅用于接收和回应广播的组件。许多广播都是来自系统代码的---例如,广播通告时区已经更改、电池电量不足、照片拍摄完成,甚至用户更改了应用程序的显示语言也需要实例化一个广播---比如说,让其它程序知道设备上已经下载了一些新的数据可供它们使用。
应用程序可以拥有多个广播接收器来响应重要的广播内容。所有的这些接收器都是从BroadcastReceiver基类中继承下来的。
广播接收器不会在用户界面上显示出来。但是,它们可能会启动一个activity来响应它们接收到的重要信息,它们或者也有有可能用NotificationManager来警示用户。这个警示可以从多个方面来引起用户的注意---或者是闪动背灯,或者是让手机震动,又或者是播放一个声音等等。它们一般会在状态栏中放置一个不动的图标,用户点击这个图标便可以查看相应的信息。
Content providers
Content provider可以产生一系列的特定数据给其它的应用程序。这些数据可以被存放在文件系统中,也可以存放在SQLite数据库,或者是别的任何可以存放数据的方式。Content provider是从ContentProvider基类中继承下来,并实例化一系列的方法来使别的应用程序去存取数据(这些数据是和这个content provider的数据类型相同)。当然了,别的程序并不是直接调用content provider的这些方法,而是用ContentResolver对象类调用它们。ContentResolver可以调用所有的content provider,它们共同协调来完成所有的内部进程间的交流。
.如果需要更多的相关信息和如何使用,请查看Content Providers文档。当有需要被某特定组件进行处理的请求时,Android会确保这个程序进程的组件处于运行状态(如果有需要则启动它),并且确保这个组件已经拥有一个实例(如果有需要则对其进行实例化)。
激活器(Activating components): intents
当Content provider接收到ContentResolver的请求时就会被触发。而另外三个组件---活动、服务、广播接收器---它们由“intent”这种异步信息来触发的。所有的intent都是包含信息的Intent对象。对于活动和服务而言,它对所请求的动作进行命名并指定在其它程序上的那些URI和数据上启动。例如,它可能传输一个请求给某一个活动来显示一张图片给用户或者让用户编辑一些文本信息。而对于广播接收器而言,这个intent对象对正在通告的广播进行命名。比如,它可能会告诉指定的部件,相机的快门已被按下了。
这里有几个触发各种组件的方法:
· 活动由Context.startAtivity()或者Activity.startActivityForResult()启动(或者是运行一些新的动作)。作出响应的活动可以通过调用getIntent()方法来查看触发它的首个intent。Android调用活动的onNewIntent()方法来传递给它下面的intent。由一个活动去触发下一个活动。如果它希望它触发的活动给它返回一个结果,那它就应调用startActivityForResult()而不是startAntivity()。例如,如果它启动一个活动来使用户选择一张图片,它会希望能够返回被选择的那张图片。这个结果是通过一个intent对象调用活动的onActivityResult()方法来返回的,
服务由传递intent对象给Context.startService()方法来启动(或者是运行一些新的动作)的。Android调用服务的onStartCommand()方法并给它传递一个intent对象。
· 类似地intent对象可以传递给ContextlbindService()方法来建立一个调用组件和指定服务的连接。而这个服务通过调用onBind()接受到这个intent对象。(如果服务没有处于运行状态,bindService()可以选择性地启动它)比如,活动可能与一个前面提到的音乐后台播放服务建立连接,这样它就可以为用户提供一些方法(通过一个用户界面)来控制这个后台播放。活动需要调用bindService()来设置这个连接,然后才能调用服务定义的勇于控制后台播放的方法。
· 应用程序可以通过传递intent对象给Context.sendBroadcast(),Context.sendOrderedBroadcast(),和Context.sendStickyBroadcast()这些方法的任何一个variation来启动一个广播。Android传送intent给所有需要它的广播接收器,这些广播接收器通过调用onReceive()方法来接收。想要了解更多关于intent的信息,请查阅相关文章Intent and Intent Filters。
关闭组件(Shutting down components)
Content provider仅当它响应ContentResolver的请求时才会处于工作状态。而广播接收器仅当它响应广播信息时才会工作。所以没有必要去显式地关闭这些组件。
但是对于提供用户界面的活动而言,它们与用户是处于长期的对话状态,只要这个对话状态正在持续,即使程序空闲着,它们依然会处于活跃之中。类似地,服务业可能会运行很长的一段时间。所以Android需要通过调用方法的方式去关闭这些活动和服务。
· 活动可以通过调用它的finish()方法来停止运行。而一个活动也可以通过调用finishActivity()方法来关闭另一个活动(前提是这个活动是由前一个活动通过调用startActivityForResult()方法来启动的)。
· 方法可以通过调用stopSelf()方法来停止,或者通过调用Context.,stopService()来停止。
组件如果不需要继续使用了或者Android必须要回收内存给其它更多的活动组件时,也可以被系统关闭。在Component Lifecycles这部分内容中会专门讨论这个回收组件的情况。