框架论题:应用程序基础
Android applications are written in the Java programming language. The compiled Java code — along with any data and resource files required by the application — is bundled by the aapt
tool into an Android package, an archive file marked by an .apk
suffix. This file is the vehicle for distributing the application and installing it on mobile devices; it's the file users download to their devices. All the code in a single .apk
file is considered to be one application.
Android应用是由Java编程语言写成的。经过编译的Java代码——以及应用所需的所有数据和资源文件——都由aapt
工具绑到一个Android包里面去,这是一个扩展名为.apk的归档文件。该文件是发布应用或是在移动设备上安装应用的手段;她也是用户下载到他们设备的那个文件。所有的代码都在一个单一的.apk文件中,而该文件也被认为是一个应用。
In many ways, each Android application lives in its own world:
从许多方面来看,每一个Android应用都生存在她自己的世界里:
- By default, every application runs in its own Linux process. Android starts the process when any of the application's code needs to be executed, and shuts down the process when it's no longer needed and system resources are required by other applications.
默认地,每一个应用都运行在她自己的Linux进程中。当需要执行任何应用代码的时候,Android就会启动进程,而当该代码不再执行、并且其他的应用又在请求系统资源的时候,Android就关闭该进程。 - Each process has its own virtual machine (VM), so application code runs in isolation from the code of all other applications.
每个进程有她自己的虚拟机(VM),所以某个应用的代码在运行时,和其他所有的应用代码都是隔离的。 - By default, each application is assigned a unique Linux user ID. Permissions are set so that the application's files are visible only to that user and only to the application itself — although there are ways to export them to other applications as well.
默认地,每一个应用都被赋予一个唯一的Linux用户ID。权限设定为该应用的文件只有用户和该应用本身才可见——尽管有别的方法也可以将这些权限放给其他的应用。
It's possible to arrange for two applications to share the same user ID, in which case they will be able to see each other's files. To conserve system resources, applications with the same ID can also arrange to run in the same Linux process, sharing the same VM.
有可能安排2个应用共享一个用户ID,此时此景,他们将能够“看见”彼此的文件。为了节约系统资源,同一个ID的应用,都将在同一个Linux进程中运行,分享同一个虚拟机。
========================================
Application Components
应用的组件
A central feature of Android is that one application can make use of elements of other applications (provided those applications permit it). For example, if your application needs to display a scrolling list of images and another application has developed a suitable scroller and made it available to others, you can call upon that scroller to do the work, rather than develop your own. Your application doesn't incorporate the code of the other application or link to it. Rather, it simply starts up that piece of the other application when the need arises.
Android最重要的特性是一个用用可以成为其他应用的元素(假设其他的应用许可)。比如,如果你的应用需要显示一个图片的滚动列表,而另一个应用已经开发了一个合适的滚动列表,并且使其对其他应用可见,那么你就可以呼叫该滚动列表完成这项工作,而不是开发自己的滚动列表。你的应用不需要包含其他应用的代码,也不需要链接到其他应用。在需要的时候,你只需简单地启动其他应用中的某个代码片段。
For this to work, the system must be able to start an application process when any part of it is needed, and instantiate the Java objects for that part. Therefore, unlike applications on most other systems, Android applications don't have a single entry point for everything in the application (no main()
function, for example). Rather, they have essential components that the system can instantiate and run as needed. There are four types of components:
为实现上述愿景,当需要应用的任何部分之时,系统必须能启动一个应用进程,并且针对所请求的部分来实例化Java对象。所以,不像其他大多数系统中的应用那样,Android应用没有“单一入口点”(比如,没有main()函数)。进而,Android应用有本质的组件,这些组件可由系统按需实例化来运行。这些组件分为4类:
Activity
base class.An application might consist of just one activity or, like the text messaging application just mentioned, it may contain several. What the activities are, and how many there are depends, of course, on the application and its design. Typically, one of the activities is marked as the first one that should be presented to the user when the application is launched. Moving from one activity to another is accomplished by having the current activity start the next one.
一个应用可能由仅有的一个活动组成,或者,像之前提到的文字短信应用那样,由几个活动组成。究竟什么是活动?在应用和设计之中彼此如何依赖?一般说来,应用中的一个活动被标识为应用启动时展现给用户的第一个活动。从一个活动移动到另一个活动的行为,是由当前活动启动下一个活动。
Each activity is given a default window to draw in. Typically, the window fills the screen, but it might be smaller than the screen and float on top of other windows. An activity can also make use of additional windows — for example, a pop-up dialog that calls for a user response in the midst of the activity, or a window that presents users with vital information when they select a particular item on-screen.
每个活动都被给予一个默认的画画窗口。一般说来,该窗口充满了屏幕,但他也可能小于屏幕,且浮动于其他窗口之上。一个活动也可以被当作附加窗口来使用——比如说,在活动中接受用户响应的弹出式对话框,或是选择了屏幕上的特定目标时提示用户重要信息的一个窗口。
The visual content of the window is provided by a hierarchy of views — objects derived from the base View
class. Each view controls a particular rectangular space within the window. Parent views contain and organize the layout of their children. Leaf views (those at the bottom of the hierarchy) draw in the rectangles they control and respond to user actions directed at that space. Thus, views are where the activity's interaction with the user takes place. For example, a view might display a small image and initiate an action when the user taps that image. Android has a number of ready-made views that you can use — including buttons, text fields, scroll bars, menu items, check boxes, and more.
窗口的可视化内容由视图的层次化体系所提供——这些对象都继承自基类View
。每个视图控制着窗口中特定的矩形空间。父视图包含并组织着其儿子的布局。画在矩形中的叶子视图(层次化体系的底层),他们直接控制并响应该矩形空间中的用户行为。这样,视图是活动与用户交互的地方。比如说,一个视图可以展示一个小图片,并当用户点击图片时初始化某个行为。Android有一些现成的视图供你使用——包括按钮、文本框、滚动条、菜单项、复选框,及其它。
A view hierarchy is placed within an activity's window by the
method. The content view is the View object at the root of the hierarchy. (See the separate User Interface document for more information on views and the hierarchy.) Activity.setContentView()
视图层次体系由活动窗口的
方法来部署。内容视图是位于层次体系的根中的View对象。(参阅User Interface文档,获取有关视图和层次体系的更多信息)Activity.setContentView()
Service
base class. Service
基类。A prime example is a media player playing songs from a play list. The player application would probably have one or more activities that allow the user to choose songs and start playing them. However, the music playback itself would not be handled by an activity because users will expect the music to keep playing even after they leave the player and begin something different. To keep the music going, the media player activity could start a service to run in the background. The system would then keep the music playback service running even after the activity that started it leaves the screen.
基本的例子就是从播放列表中播放歌曲的媒体播放机。播放机应用可能有一个或多个活动,该应用允许用户选择歌曲并开始播放。但音乐播放本身并不需要由某个活动来处理,因为用户会希望在他们退出播放机去做些其他事情的时候,音乐还能够接着播放。为使音乐继续,媒体播放机活动会启动一个服务来在后台运行。接着,系统会让音乐回放服务一直运行着,即使启动该服务的活动已经退出屏幕了。
It's possible to connect to (bind to) an ongoing service (and start the service if it's not already running). While connected, you can communicate with the service through an interface that the service exposes. For the music service, this interface might allow users to pause, rewind, stop, and restart the playback.
实践中,我们也可以连接到(绑定到)一个正在跑的服务上(要是该服务还没开始跑,也可以启动她)。连上去以后,你可以通过服务所提供的接口与之通信。对于音乐服务而言,该接口可能会允许用户暂停、倒带、停止和重放播放列表。
Like activities and the other components, services run in the main thread of the application process. So that they won't block other components or the user interface, they often spawn another thread for time-consuming tasks (like music playback). See Processes and Threads, later.
如同活动和其他的组件一样,服务运行在应用进程的主线程中。因此,服务不会阻塞其他的组件或用户界面,他们常常再生出耗时任务(比如音乐回放)的另一个线程。参见后面的Processes and Threads部分。
- Broadcast receivers 广播接收器
- A broadcast receiver is a component that does nothing but receive and react to broadcast announcements. Many broadcasts originate in system code — for example, announcements that the timezone has changed, that the battery is low, that a picture has been taken, or that the user changed a language preference. Applications can also initiate broadcasts — for example, to let other applications know that some data has been downloaded to the device and is available for them to use.
- 广播接收器是一个除了接收和响应广播通知以外啥也不做的组件。许多广播源自系统代码——比如,通知时区改变,电池低电,图像获取,或是用户改变了语言设置。应用也能发起广播——比如,让别的应用知道有些数据已经下载到设备了,可以供她们使用了。
-
An application can have any number of broadcast receivers to respond to any announcements it considers important. All receivers extend the
BroadcastReceiver
base class. -
应用会有任意数量的广播接收器来响应每一条她认为重要的广播。所有的接收器扩展自
BroadcastReceiver
基类。Broadcast receivers do not display a user interface. However, they may start an activity in response to the information they receive, or they may use the
NotificationManager
to alert the user. Notifications can get the user's attention in various ways — flashing the backlight, vibrating the device, playing a sound, and so on. They typically place a persistent icon in the status bar, which users can open to get the message. -
广播接收器并不显示用户界面。但是,他们可以启动活动来响应所收到的信息,或者她们可以用
NotificationManager
来警告用户。通知能以许多方式引起用户的注意——背光闪烁,设备震动,播放声音,及其它。他们通常会在状态栏上放置一个持久的图标,用户可以通过打开该图标来获得信息。 - Content providers 内容提供者
- A content provider makes a specific set of the application's data available to other applications. The data can be stored in the file system, in an SQLite database, or in any other manner that makes sense. The content provider extends the
ContentProvider
base class to implement a standard set of methods that enable other applications to retrieve and store data of the type it controls. However, applications do not call these methods directly. Rather they use aContentResolver
object and call its methods instead. A ContentResolver can talk to any content provider; it cooperates with the provider to manage any interprocess communication that's involved. - 内容提供者产生应用数据的规范集合,该集合对于其他应用来说是可用的。数据可以存储在文件系统里,在SQLite数据库里,或是任何有意义的地方。内容提供者扩展自
ContentProvider
基类,并实现了一个标准的方法集合,这使得其他应用能存取她所控制的这类数据。但是,应用并不直接呼叫这些方法;而是使用ContentResolver
对象,并呼叫其方法。ContentResolver可以和所有的内容提供者交互,她与内容提供者合作,管理应用所涉及的所有进程内部通信。 -
See the separate Content Providers document for more information on using content providers.
-
参见分出来的Content Providers文档获取使用内容提供者的更多信息。
Whenever there's a request that should be handled by a particular component, Android makes sure that the application process of the component is running, starting it if necessary, and that an appropriate instance of the component is available, creating the instance if necessary.
无论何时,只要有需要特定组件处理的请求,Android就会确保运行该组件的应用进程(按需启动),并且有一个可用的、合适的组件实例(按需创建)。
Activating components: intents 激活组件:意向
Content providers are activated when they're targeted by a request from a ContentResolver. The other three components — activities, services, and broadcast receivers — are activated by asynchronous messages called intents. An intent is an Intent
object that holds the content of the message. For activities and services, it names the action being requested and specifies the URI of the data to act on, among other things. For example, it might convey a request for an activity to present an image to the user or let the user edit some text. For broadcast receivers, the Intent object names the action being announced. For example, it might announce to interested parties that the camera button has been pressed.
当内容提供者被一个来自ContentResolver的请求所对准时,她就会被激活。其他的三种组件:活动、服务和广播接收器——都是被称为“意向”(intent)的异步消息所激活。一个意向就是一个Intent
对象,该对象握有消息的内容。对于活动和服务而言,意向,意味着所请求的行动以及指定所需操作数据的URI。例如,意向也许传达了要活动给用户展示一张图片的请求,或是让用户编辑一些文字。对广播接收器来说,Intent对象命名了所宣告的行动。例如,意向也许宣告了相机按钮的特定的部分被按下了。(这部分译得不好,很费解)
There are separate methods for activating each type of component:
激活每种组件的不同方法:
- An activity is launched (or given something new to do) by passing an Intent object to
orContext.startActivity()
. The responding activity can look at the initial intent that caused it to be launched by calling itsActivity.startActivityForResult()
method. Android calls the activity'sgetIntent()
method to pass it any subsequent intents.onNewIntent()
向
或是Context.startActivity()
Activity.startActivityForResult()传入一个Intent对象来启动活动。负责响应的活动会呼叫自身的
方法来查看初始的、导致她启动的intent。Android呼叫活动的getIntent()
方法向其传入后续的intents.onNewIntent()
One activity often starts the next one. If it expects a result back from the activity it's starting, it calls
startActivityForResult()
instead ofstartActivity()
. For example, if it starts an activity that lets the user pick a photo, it might expect to be returned the chosen photo. The result is returned in an Intent object that's passed to the calling activity's
method.onActivityResult()
一个活动经常会启动下一个活动。如果她期望从她所启动的活动中获得反馈,她就会呼叫startActivityForResult()
,而非startActivity()
. 例如:活动A启动了另一个活动B,B让用户选择一张图片,那么A也许会希望B能够返回被选中的图片。该选择的结果会被放在一个Intent对象中被返回,这个对象是被传入活动A的
。onActivityResult()的那个Intent对象
-
A service is started (or new instructions are given to an ongoing service) by passing an Intent object to
. Android calls the service'sContext.startService()
method and passes it the Intent object.onStart()
通过向
传入一个Intent对象,来启动服务(或是向正在运行的服务送出新的指令)。Android呼叫服务的Context.startService()
onStart()方法并向其传入Intent对象。
Similarly, an intent can be passed to
to establish an ongoing connection between the calling component and a target service. The service receives the Intent object in anContext.bindService()
call. (If the service is not already running,onBind()
bindService()
can optionally start it.) For example, an activity might establish a connection with the music playback service mentioned earlier so that it can provide the user with the means (a user interface) for controlling the playback. The activity would callbindService()
to set up that connection, and then call methods defined by the service to affect the playback.
类似地,intent能被传给
,以在主叫组件和目标服务之间建立一个持续的连接。服务从Context.bindService()
呼叫中收取Intent对象。(如果服务尚未运行,那么onBind()
bindService()会有选择地启动她。)例如,活动A可能与之前提到的音乐播放服务建立连接,由此,活动A就能够像用户提供一个有意义的用户界面来控制音乐的播放。活动可以呼叫
bindService()来建立连接,然后呼叫由服务所定义的方法来影响音乐的播放。
A later section, Remote procedure calls, has more details about binding to a service.
后面的Remote procedure calls(远程过程呼叫)有关于绑定服务的更多细节。 -
An application can initiate a broadcast by passing an Intent object to methods like
,Context.sendBroadcast()
, andContext.sendOrderedBroadcast()
in any of their variations. Android delivers the intent to all interested broadcast receivers by calling theirContext.sendStickyBroadcast()
methods.onReceive()
应用能通过向类似
的方法传入一个Intent对象来初始化广播。通过呼叫Context.sendBroadcast()、
和Context.sendOrderedBroadcast()
Context.sendStickyBroadcast()
方法,Android会向所有感兴趣的广播接收器传递这个intent。onReceive()
For more on intent messages, see the separate article, Intents and Intent Filters.
更多关于intent消息的信息,参阅:Intents and Intent Filters(意向与意向过滤器)。
(未完待续……)
===========================================Shutting down components 关闭组件
A content provider is active only while it's responding to a request from a ContentResolver. And a broadcast receiver is active only while it's responding to a broadcast message. So there's no need to explicitly shut down these components.
内容提供者只有当她正在响应源自ContentResolver的请求时才处于激活状态。广播接收器只有在她响应广播消息时才处于激活状态。所以,不必显式地关闭这些组件。
Activities, on the other hand, provide the user interface. They're in a long-running conversation with the user and may remain active, even when idle, as long as the conversation continues. Similarly, services may also remain running for a long time. So Android has methods to shut down activities and services in an orderly way:
另一方面,活动提供了用户界面。他们和用户将会有一个长时间运行的对话,即使闲着没事干,这种对话也在持续。类似地,服务也可以长时间地保持运行。所以Android有多种方法下面的顺序来关闭活动和服务:
- An activity can be shut down by calling its
method. One activity can shut down another activity (one it started withfinish()
startActivityForResult()
) by calling
.finishActivity()
呼叫活动的
方法,可以关闭活动。活动A通过呼叫finish()
可以关闭另一个活动B(B是由A通过finishActivity()
startActivityForResult()
启动的) - A service can be stopped by calling its
method, or by callingstopSelf()
.Context.stopService()
可以通过呼叫服务的
或stopSelf()
来禁用服务。Context.stopService()
Components might also be shut down by the system when they are no longer being used or when Android must reclaim memory for more active components. A later section, Component Lifecycles, discusses this possibility and its ramifications in more detail.
当组件不再被使用,或者Android必须回收内存给更多的激活组件时,组件也可以由系统来关闭。后面Component Lifecycles的章节,讨论了这种可能性,及其各种可能的后果。
The manifest file 清单文件
Before Android can start an application component, it must learn that the component exists. Therefore, applications declare their components in a manifest file that's bundled into the Android package, the .apk
file that also holds the application's code, files, and resources.
在Android能启动一个应用组件之前,Android必须知晓组件的存在。所以,应用在一个清单文件中声明了她们的组件,该文件被绑到android包中,这个.apk文件也握有应用的代码、文件和资源。
The manifest is a structured XML file and is always named AndroidManifest.xml for all applications. It does a number of things in addition to declaring the application's components, such as naming any libraries the application needs to be linked against (besides the default Android library) and identifying any permissions the application expects to be granted.
清单文件时结构化的XML文件,在所有的应用中,她的名字总是AndroidManifest.xml。除了声明应用的组件以外,她还做许多事情,比如命名应用中的各种需要链接的库(包括默认的Android库),还要定义应用所希望被授予的所有许可权限。
But the principal task of the manifest is to inform Android about the application's components. For example, an activity might be declared as follows:
但是清单文件最主要的工作还是向Android通告应用的组件。例如,一个活动可以声明成下面这样:
<?xml version="1.0" encoding="utf-8"?>
<manifest . . . >
<application . . . >
<activity android:name="com.example.project.FreneticActivity"
android:icon="@drawable/small_pic.png"
android:label="@string/freneticLabel"
. . . >
</activity>
. . .
</application>
</manifest>
The name
attribute of the <activity>
element names the Activity
subclass that implements the activity. The icon
and label
attributes point to resource files containing an icon and label that can be displayed to users to represent the activity.
<activity>
要素的name属性命名了实现了活动的Activity子类。icon和label属性指向包含了图标和标签的资源文件,这些文件能展示给用户以表现活动。
The other components are declared in a similar way — <service>
elements for services, <receiver>
elements for broadcast receivers, and <provider>
elements for content providers. Activities, services, and content providers that are not declared in the manifest are not visible to the system and are consequently never run. However, broadcast receivers can either be declared in the manifest, or they can be created dynamically in code (as BroadcastReceiver
objects) and registered with the system by calling
.Context.registerReceiver()
其他的组件以类似的方式来声明——<service>元素是服务,
<receiver>
元素是广播接收器,还有<provider>
是内容提供者。对于系统来说,清单文件中没有声明的活动、服务和内容提供者都是不可见的,因此也永远不会运行。但是,广播接收器既可以在清单文件中声明,也可以由代码动态地创建(就像BroadcastReceiver
对象),并且可以通过呼叫Context.registerReceiver()被注册到系统中。
For more on how to structure a manifest file for your application, see The AndroidManifest.xml File.
更多如何为应用构造清单文件的内容,参见The AndroidManifest.xml File。
Intent filters
An Intent object can explicitly name a target component. If it does, Android finds that component (based on the declarations in the manifest file) and activates it. But if a target is not explicitly named, Android must locate the best component to respond to the intent. It does so by comparing the Intent object to the intent filters of potential targets. A component's intent filters inform Android of the kinds of intents the component is able to handle. Like other essential information about the component, they're declared in the manifest file. Here's an extension of the previous example that adds two intent filters to the activity:
一个intent对象可以显式地命名一个目标组件。如果这么做,Android会寻找该组件(基于清单文件的声明)并且激活她。但是如果目标并未被显式地命名,那么Android就必须定位最佳组件来响应该intent. 这是通过比较Intent对象和潜在目标的intent过滤器的过程来进行的。组件的intent过滤器向Android通告了组件所能处理的intents的种类。就像组件的其他基本信息一样,组件的intent过滤器被定义在清单文件之中。这里是前面例子的扩展,其中添加了2个活动的intent过滤器:
<?xml version="1.0" encoding="utf-8"?>
<manifest . . . >
<application . . . >
<activity android:name="com.example.project.FreneticActivity"
android:icon="@drawable/small_pic.png"
android:label="@string/freneticLabel"
. . . >
<intent-filter . . . >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter . . . >
<action android:name="com.example.project.BOUNCE" />
<data android:mimeType="image/jpeg" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
. . .
</application>
</manifest>
The first filter in the example — the combination of the action "android.intent.action.MAIN
" and the category "android.intent.category.LAUNCHER
" — is a common one. It marks the activity as one that should be represented in the application launcher, the screen listing applications users can launch on the device. In other words, the activity is the entry point for the application, the initial one users would see when they choose the application in the launcher.
例子中的第一个过滤器——将行为"android.intent.action.MAIN
"和分类"android.intent.category.LAUNCHER
"结合在了一起——是常见的一种过滤器。她使得活动会在应用启动的时候就被展示出来,屏幕列出了用户可以在设备上启动的应用。换句话说:该活动是应用的入口点,是用户在启动器中选择该应用后所能看到的最开始的那个应用。
The second filter declares an action that the activity can perform on a particular type of data.
第二个过滤器声明了一个行动,这使得该活动能够在特定的数据类型上执行此项行动。
A component can have any number of intent filters, each one declaring a different set of capabilities. If it doesn't have any filters, it can be activated only by intents that explicitly name the component as the target.
一个组件能有任意数量的intent过滤器,每一个过滤器都声明了不同的能力集合。如果组件没有任何过滤器,那么她就只能被显式地定向到该组件的intents所激活。
For a broadcast receiver that's created and registered in code, the intent filter is instantiated directly as an IntentFilter
object. All other filters are set up in the manifest.
为获知代码中创建和注册的广播接收器,intent过滤器需要直接由一个IntentFilter
对象所实例化。所有其他的过滤器都是在清单文件中配置的。
For more on intent filters, see a separate document, Intents and Intent Filters.
为获得更多的intent过滤器的信息,参见文档:Intents and Intent Filters。
(未完待续)