Android 应用程序使用 Java 编程语言开发的。Android SDK 将你的代码和相关的资源文件编译成 .apk 文件:Android 应用程序包。一个 APK 文件包含了 Android 应用程序所需的所有文件,它就是可以安装在 Android 设备上的 app 。

一旦一个应用安装在了 Android 设备上,那么它就运行在它自己的安全沙箱里:

  1. Android 操作系统是一个多用户的 Linux 操作系统,在这个系统里,每一个应用程序都是一个用户。

  2. 默认情况下,系统会为每一个应用程序指定一个 Linux User ID(这个 ID 只有 Android 系统知道,App 是不知道的)。系统为每一个 App 程序下的文件都设置了访问权限,因此只有 User ID 匹配的应用程序才能访问指定文件。

  3. 每一个进程都拥有自己独立的虚拟机,因此,每一个应用程序都是独立运行的。

  4. 默认情况下,每一个应用程序都运行在它自己独立的进程里面。当应用程序中的任何一个组件需要执行任务时,Android 系统便会启动进程,当程序中不再需要执行任何任务时或者系统为其他应用程序恢复内存时,此程序的进程便会停止。

按照这种方式,Android 实现了“最少利用原则”。也就是说,默认情况下,一个应用只访问需要执行任务的组件,并不访问其他的组件。这样便创建了一个非常安全的运行环境:一个应用程序只能访问那些系统给它权限的部分。

但是依然有很多办法去让 App 之间共享数据和访问系统的服务:

  1. 可以为两个 App 指派同一个 User ID,这样之后,他们就可以访问彼此的文件了。为了节省资源,拥有相同 User ID 的应用程序会运行在同一个进程中,并且共享同一个虚拟机(前提是这两个 App 具有相同的签名文件)。

  2. 一个应用程序可以访问移动终端设备上的文件,例如:手机联系人,短信,SD 卡,相机,蓝牙等等。所有的这些权限只有在安装时通过用户的同意才可以正常使用。

上面讲述了一个 App 在 Android 系统中的存在方式,下面将会为你讲述:

1. 应用程序的核心组件(四大组件);

2. 清单文件(声明四大组件和应用程序所需特性的位置);

3. 资源文件(有别于代码,主要用于布局文件,有了这个文件,你便可以优雅的处理不同配置的设备)。

一、应用程序组件。

四大组件是 Android 应用程序的核心构造块。每一个组件都是不同的,系统可以通过任何组件进入到你的应用中。但对于用户来说,并不是所有的组件都是入口点,有些组件必须依赖另一些组件,话虽如此,但是每一个都是特别的,都有自己的特性,都是不可或缺的 Android 应用程序构造块。

Android 系统中共有四大组件。每一个组件都有自己特定的功能,并且每一个组件都有其自己独特的生命周期。

1. 下面便是四大组件的详细介绍:

Activity

一个 Activity 代表了一个单独的用户界面。例如:一个邮箱 App 可能有一个展示邮件列表的 Activity,有一个创建邮件的 Activity,有一个阅读邮件的 Activity。尽管这些 Activity 构成了邮箱 App,但是它们中的每一个却都是独立的。正是因为这个,所以其他应用程序可以访问邮箱 App 中的任何一个 Activity(如果邮箱 App 允许)。例如:为了分享新拍摄的照片,一个摄像 App 可以打开邮箱 App 中创建新邮件的 Activity。

我们创建的每一个 Activity 都是 Activity 的子类。

Service

Service 是一个在后台执行长期运行或者远程任务的组件。Service 并不提供用户界面。例如:当用户在其他应用中和 Activity 交互时,一个 Service 可能在后台播放音乐;或者在不阻塞线程的情况下,从服务器端获取数据。其他的组件,像 Activity,可以启动或者绑定 Service(如果需要和 Service 交互)。

我们创建的每一个 Service 都是 Service 的子类。

Content providers

Content providers 管理一系列的共享数据。你可以在文件系统中保存你的文件,或者在数据库、网络端,或者其他任何你的应用程序可以访问的地方。通过 Content providers 其他应用程序可以访问甚至更改这些数据(如果 Content providers 允许)。例如:Android 系统利用 Content providers 管理手机联系人。正因为如此,只要一个 App 拥有合适的权限,那么就可以获取手机联系人的信息。

Content providers 也支持读、写隐私数据操作。例如:Not Pad 应用就是利用 Content providers 完成的。

我们创建的每一个 Content providers 都是 Content providers 的子类。

Broadcast receivers

Broadcast receivers 是一个可以接收系统级广播的组件。很多广播都是系统生成的,例如:手机屏幕点亮的广播,手机电量低的广播,照片拍摄成功的广播。当然一个 App 也可以创建广播,例如:发出一个广播去通知其他应用程序,某些数据已经下载成功,并且它们可以访问这些数据。尽管广播也不提供用户交互的界面,但是当Broadcast receivers 接收到广播时,它们可以创建一个通知栏。和其他组件一样,Broadcast receivers 也只是其他组件的一个接入点,在这个组件里,只能做一些短时操作,不能做任何耗时操作。

我们创建的每一个Broadcast receivers 都是 Broadcast receivers 的子类。

Android 系统设计的独到之处是:任何 App 都可以启动其他 App 里面的组件。例如:如果你想让用户去拍摄一张照片,那么你可以直接调用拥有拍照功能的 App,而不是自己重新创建一个拍照 Activity。你不需要去集成拍照 App,你甚至不用在拍照 App 里面写链接的代码。你要做的就是直接在你的应用程序里面启动拍照 App,当拍照完成之后,所拍摄的照片就会返回到你的应用中。对用户来说,就像你的应用程序有拍照功能一样。

当系统启动一个组件时,便会启动组件所在的进程(如果进程尚未启动),并且初始化和组件相关的类。例如:当你启动拍照 App 中的拍照 Activity 时,这个 Activity 便会运行在拍照 App 的进程中,并不是你的应用程序进程。因此,不像其他系统,Android 系统是没有 main() 函数的。

因为 Android 系统中的应用程序都运行在独立的进程中,并且每一个应用程序的文件都有严格访问权限,所以你的应用程序并不能直接启动其他应用程序里面的组件。但是 Android 系统可以。因此为了启动其他应用程序里面的组件,你必须向 Android 系统发送一条“启动某应用程序组件”的信息,然后又 Android 系统帮你启动指定组件。

2. Activating Components

四大组件中的三个组件(Activity、Service、Broadcast receiver)都可以被 Intent 激活。Intent 将一个组件和其他组件绑定起来(你可以将它当成信息的传递者),无论这个组件是否属于你的应用程序。

Intent 对象是通过 Intent 构造函数创建的,在 Intent 里面指定特定的组件或者某一类型的组件(一个 Intent 可以显示的,也可以是隐式的)。

对于 Activity、Service 来说,Intent 定义了需要执行的动作,或者传递的数据(Activity 或者 Service 执行时需要的一些数据)。例如:一个 Intent 可能传递给 Activity 一个展示图片或者打开网页的请求。在某些情况下,你可以通过打开一个 Activity 去接受一些返回值(例如:你可以通过 Intent 发送一个“选择联系人信息”的请求,当那个 Activity 执行完毕,就会返回指定联系人的 Uri)。

对于 Broadcast receiver 来说,Intent 只是定义了广播的内容(例如:一个设备电量低的广播只是包含了“ battery is low ”信息)。

Content Provider 并不是由 Intent 激活的。它是由 ContentResolver 对象激活的。

下面就是激活每一种组件的方法:

1.你可以通过向 startActivity() 或者 startActivityForResult()(当你想要接收到返回值时)传递 Intent 启动一个 Activity。

2.你可以通过向 startService() 函数传递 Intent 启动 Service,或者向 bindService() 函数传递 Intent 绑定 Service。

3.你可以通过向 sendBroadcast(), sendOrderedBroadcast(),或者 sendStickyBroadcast() 函数传递 Intent 来初始化 Broadcast。

4.你可以通过调用 ContentResolver 的 query() 函数来启动 Content Provider。

二、清单文件。

在 Android 系统启动应用组件之前,都会先到清单文件里面读取此应用所包含的组件信息。因此,你的必须在清单文件里面声明此所有包含的所有组件,清单文件就在 App 的根目录下。

清单文件除了声明应用程序所包含的组件之外,还有一下功能:

1.确认应用程序所需的权限;

2.声明 API 的最低等级;

3.声明应用程序所需的硬件特性;

4.应用程序所需链接的库文件(例如:Google Map Library);

5.等等。

1. Declaring components

清单文件最主要的任务就是:告诉系统此应用程序所有组件的信息。例如:一个清单文件可以这样声明它的组件:

<?xml version="1.0" encoding="utf-8"?><manifest ... >    <application android:icon="@drawable/app_icon.png" ... >        <activity android:name="com.example.project.ExampleActivity"                  android:label="@string/example_label" ... >        </activity>        ...    </application></manifest>

在上面的 application 元素里,icon 属性定义了应用程序的图标。

在 Activity 元素里,name 属性指定了 Activity 的完整名称。

你必须按照以下的方式声明所有的组件:

a. activity 元素声明 Activity;

b. service 元素声明 Service;

c. receiver 元素声明 Broadcast receiver;

d. provider 元素声明 Content Provider。

如果你不在清单文件里面声明 Activity、Service、Content Provider,那么系统便不会识别这些组件,因此这些组件也不会正常的执行。但是 Broadcast receiver 却是一个很特殊的组件,你可以在清单文件里面声明这个组件,或者在代码里面动态注册,它都是正确执行的。

2. Declaring component capabilities (声明组件的能力)

正如上面所说,你可以通过 Intent 激活组件。你只需在构建 Intent 的时候指定目标组件名就可以了。但是 Intent 的真正强大之处并不在此,而是在于隐式意图。隐式意图只是简简单单的定义需要执行的动作,之后系统便会在设备上寻找那些可以响应此 Intent 的组件。如果在一个设备存在多个组件可以响应此 Intent,那么就会弹出一个对话框让用户进行选择最终由哪个组件来响应此 Intent。

系统通常是通过比较 Intent 和清单文件中各组件声明的 Intent Filter 来决定启动哪个组件。

当你在清单文件中声明应用程序所需组件时,你可以有选择的声明 Intent Filter,如果你声明了这些,那就说明你的这个组件可以响应来自其他应用程序的 Intent。你可以通过向组件声明元素中添加子元素<Intent Filter>的方式声明组件的能力。例如:

<manifest ... >    ...    <application ... >        <activity android:name="com.example.project.ComposeEmailActivity">            <intent-filter>                <action android:name="android.intent.action.SEND" />                <data android:type="*/*" />                <category android:name="android.intent.category.DEFAULT" />            </intent-filter>        </activity>    </application></manifest>

然后如果某个应用程序创建了个一个ACTION_SEND,并且将它传递给了 startActivity() 函数,那么系统就有可能启动你的这个Activity。

3. Declaring app requirements

当今世界有各种各样的 Android 手机,并且它们拥有各种各样的功能。因此阻止那些没有你应用所需特性的设备安装你的应用是十分必要的。通常情况下,你可以在清单文件里面做这些工作,并且Android 系统并不会读取这些信息,只有一些“额外”的服务,像Google Play 去读区这些信息。Google Play 将通过这些特性来阻止那些没有指定硬件特性的设备搜索到这些应用。

例如,如果你的应用程序需要摄像功能,并且 API 最低版本是7,那么可以这么做:

<manifest ... >    <uses-feature android:name="android.hardware.camera.any"                  android:required="true" />    <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19" />    ...</manifest>

这样以后,在 Google Play 中,那些没有摄像功能和 API 等级小于7的设备,都不能在安装你的应用程序了。

然后,你还可以在清单文件里声明摄像头特性为“非必需”特性。要达到这样的效果,你必须在清单文件中声明:android:required="false",这样之后,你就可以在运行时检查当前设备是否支持此特性,如果不支持,只需要在程序中屏蔽掉此功能即可。

三、App Resources。

Android 应用程序并不仅仅是由代码组成的,除了代码之外,还有图片资源文件、音频文件和其他一些跟界面相关的资源文件。例如:你应该自己去定义动画、样式、颜色和布局文件。通过利用资源文件,你可以在不更改代码的前提下去适配各种不同配置的设备。

Android SDK 将会为你的资源文件生成唯一的 ID,这样之后,你就可以在代码里,或其他 XML 布局文件里面直接访问这些资源文件了。例如:你的应用程序有一个叫 logo.png 图片,保存在 res/drawable/ directory 目录下,Android SDK 将会为它生成一个叫 R.drawable.logo 的名字(这个名字,你可以在程序里面的任何位置应用它)。

将资源文件独立于代码的最大好处是:你可以为不同的设备提供可替换的资源文件。例如:你可以在 XML 文件里面定义不同的 String 文件,并将这些字符串翻译成不同的语言放入不同的文件夹。这样以后,系统就会根据当前设备的配置去找到适合的资源的文件(例如: res/values-fr/ for French string values )。

Android 系统为可替换资源提供了很多限定词。限定词是一个很短的字符串,它通常被添加在资源文件目录的末尾,它和设备的配置是对应的。另外一个例子:你应该根据设备的朝向为你的 Activity 创建不同的布局文件。例如,当设备处于竖直方向时,你可能需要一个同样处于竖直方向的布局文件;当设备处于水平方向时,你可能更需要一个水平方向的布局文件。为了达到这样的效果,你必须创建两个布局文件,并将它们放在拥有合适限定名的目录下。这样以后,系统便会根据当前设备的朝向应用不同的资源文件。

终于翻译完了,不容易啊~

温馨提示:上面的文章都是 LZ 个人见解,主要是为了让小伙伴更容易看懂,因此或多或少添了一些词,如有什么不妥之处,往指出,共同进步~

更多相关文章

  1. Android(安卓)应用程序基础
  2. Android(安卓)SO文件的兼容和适配
  3. 活动与任务
  4. Android之NDK开发
  5. Android之Adapter用法总结
  6. Android的init过程(二):初始化语言(init.rc)解析
  7. Android(安卓)面试题
  8. android cmd adb命令安装和删除apk应用
  9. Android术语

随机推荐

  1. 为什么将 Intellij IDEA 作为日常开发的
  2. 支付路由系统演进史
  3. 小心递归中内存泄漏
  4. 想来微软实习吗?
  5. 我是怎么把博客粉丝转到公众号的
  6. 如何更好地结构化表示一个 URL?
  7. 5:Zabbix5.0 监控服务器网口流量
  8. 聊聊分布式事务
  9. nginx分发算法
  10. JavaScript算法题:查找数字在数组中的索引