应用可能需要存储大量的数据来控制其运行时的行为。其中有些数据描述了应用环境:应用名称、注册的intent和需要的许可条件等。这些数据存储在名为manifest的文件中。其他的数据也可能是要显示的图片或简单的文本字符串,以指出要使用什么样的背景颜色或字体。这些数据称为resources。所有这些信息一起构成了应用的context(上下文),在Android中对这些信息进行访问需要借助于类Context。类Activity和类Service都是对类Context的扩展,这意味着所有的activity和service都可以通过该指针访问Context类型的数据。在后续的章节中,还将描述如何使用Context对象在运行时访问应用的资源。
Android要求应用在XML文件AndroidManifest.xml中显式地描述其内容。在AndroidManifest.xml文件中,应用对内容提供者、服务、需要的权限及其他元素进行声明。应用上下文会准备好这些数据,使之在Android运行时中可用。清单文件把Android应用组织成了定义良好的结构,这个结构所有应用都必须遵守,Android操作系统由此可以在可管理的环境中加载并执行这些应用。这个结构由一个通用的目录布局和目录中一组通用的文件类型组成。可以看到,Android应用的四个组件(Activity、Service、ContentProvider和BroadcastReceiver)奠定了Android应用开发的基础(如图3-4所示)。要使用其中任何一个组件,Android应用都必须在其AndroidManifest.xml文件中包含相应的声明。Application类Android的第5个组件是Application类。但是很多Android应用没有继承类Application。因为在大多数情况下,继承类Application是不必要的,Android项目向导(project wizard)不会自动创建类Application。
几乎所有Android应用的源代码都是使用下面的这种目录结构
下面将介绍res目录在使得应用的数据可以通过Context对象来访问中所起的重要作用。
下面这段代码就是在第1章中介绍的test应用的Android清单文件。test应用的功能只是显示Android应用的基础布局。它的清单文件中包含了之前讨论过的一些基础元素
如同所有结构良好的XML文件一样,该文件的第1行是标准的XML版本声明和使用的字符编码,然后定义了一些参数并声明了整个应用所需要的权限。下面这个列表总结并介绍了用到的标签:manifestpackage="com.oreilly.demo.pa.ch01.testapp"应用组件所在的默认包。android:versionCode这是一个整数,指应用的版本号。每个应用都应该包含一个版本号,而且发布给用户的版本号应该总是递增的。通过这种方式,其他程序(如Android Market、安装包和启动包)能够很容易地根据版本号判断出哪个版本更新一些。.apk文件的文件名中应该包含这个版本号,这样可以很清楚地知道这个文件中包含的是哪个版本。android:versionName它是一个字符串,跟我们通常看到的应用的版本号更像一些,如1.0.3。这个字符串就是展示给用户的版本号(根据你的应用,或者根据其他应用)。命名规则可以自己定,但是一般来说,采用的是类似m.n.o这样的机制(可以使用任意个数字表示)来识别应用的连续变化级别。uses-permission android:name=...在TestApp manifest文件中,有4个声明描述了应用希望使用的Android特征,需要得到运行该应用的设备的用户的显式许可。当安装应用时,会要求输入许可。然后,Android会记住用户认为可以(或不可以)运行该应用,允许访问安全特征。在Android中定义了很多许可,所有许可都在Android文档中有描述(搜索android.Manifest.permission)。此外,还可以定义自己的许可,并使用它们来限制其他应用对你的应用中的功能的访问,除非用户对其他应用赋予该权限。例如,通常需要开通如下权限:ACCESS_FINE_LOCATION需要从GPS传感器获取地理位置信息。CALL_PHONE允许来自用户的电话呼叫。ACCESS_MOCK_LOCATION当在模拟器中运行时,允许获取伪位置信息。INTERNET允许建立互联网连接来检索数据。applicationlabel应用的可读标签。icon="@drawable/icon"PNG文件的文件名包含你想要用于应用的图标(icon)。在这个例子中,告诉Android SDK查找TestApp应用中res(resource)目录的子目录下的图标文件。在Android Desktop(桌面)应用中,Android将为应用使用该图标。activity现在,我们一起来看一下TestActivity的定义,首先一起来定义一些属性,其中最重要的属性如下:android:nameActivity类名称,activity的全名包括包名(该应用的包名是com.oreilly.demo.pa.ch01 .testapp),但是由于该文件总是在包的名字空间下使用,因此不需要包括包名。可以把名字简化成.TestActivity。实际上,即使是最开头的点(.)也是可有可无的。android:label当activity显示在屏幕上时,我们希望在Android屏幕上方显示的内容。在strings.xml文件中定义了和应用匹配的标签。intent-filterintent-filter告诉Android什么时候可以运行该Activity。当应用要求Android实现某个Intent时,runtime(运行时)会查看可用的Activity和Service,找到某项可以提供服务的。有两个属性可以设置:action一旦runtime确定要运行哪个应用,action会告诉Android如何启动该应用。Android会查找可以解析MAIN action的activity。Launcher启动的任意一个应用都需要有且仅有一个activity或service完成MAIN action解析。categoryAndroid中的Intent resolver使用该属性进一步限定查找其需要的Intent。因此,前提是我们希望Activity在User菜单中显示,从而用户可以通过选中该Activity来启动应用。指定LAUNCHER可以完成这一点。如果没有category属性,应用也完全可以正常工作——只是你无法从Android桌面启动应用。再次说明,通常情况下,每个应用应该是有且只有一个LAUNCHER,而且它应该和应用的启动Activity在同一个intent filter中。provider(提供者)对内容提供者的声明,name是provider类的名字,authorities是内容提供者应该处理的URI权限(URI authority)。URI权限提供了内容提供者URI的域字段,使得Android内容分辨率系统能够定位要处理的某种类型的URI的提供者。在本章后面,将详细说明客户端是如何使用内容提供者的。并且声明了一个名为TestProvider的提供者。Service(服务)对应用支持的服务的声明,其中name指定服务对应的类,label为服务提供可读的标签。我们定义了一个名为.TestService的service。Receiver(接收器)对应用支持的broadcast receiver的声明,name还是表示接收类,label为接收器提供可读的标签。我们声明了一个名为TestBroadcastReceiver的接收器。
相关资源:Android移动应用开发从入门到精通--详细书签版