Application Fundamentals

本文深入解析Android应用架构,包括四大组件(Activity、Service、Content Provider 和 Broadcast Receiver)的作用及使用方式,介绍了AndroidManifest.xml文件的重要性及其包含的关键信息,如组件声明、权限需求等。

这里写链接内容

android应用使用Java编写。android SDK工具将你的代码、数据和资源文件编译成一个APK文件:一个android package,是一个有.apk后缀的存档文件。一个APK文件包含一个app所有的内容,是一个支持android设备用于安装app的文件。
一旦安装在设备上,每个app都拥有自己的安全沙箱。

  • android操作系统是一个多用户的Linux系统,在系统中,每一个app是一个不同的用户。
  • 默认情况下,系统分配给每个app一个独一无二的用户ID(这个ID只被系统使用,app本身不知道)。系统给app中的所有文件设置权限,所以只有分配给这个app的用户ID才能访问他们。
  • 每个进程有自己的虚拟机,所以每个app的代码相对于其他app来说都是孤立运行的。
  • 默认情况下,每个app运行在自己的Linux进程中。当app的组件需要运行时,android启动进程,当不在需要执行时或者当系统必须将内存给其他APP时关闭进程。
    用这个种方法,android系统实现了最小权限原则。也就是,默认情况下,每个app只能访问自己的组件,然后要求它工作。这就创建了一个非常安全的环境,每个app都不能访问系统没给权限的部分。
    然而,还是有方法让一个app分享数据给其他app或者让app访问系统的服务。
  • 给两个app分配一个公用的Linux用户ID是可以的,这样,他们能够访问对方的文件。为了保护系统资源,拥有相同用户ID的app可以被安排在同一个Linux进程中,共用一个VM(app必须被分配相同的认证)。
  • app可以请求权限来访问设备数据,比如说用户的通讯录,SMS信息,SD卡,camera,Bluetooth等等。所有权限必须在用户安装时给予。
    关于一个app如何存在在系统中,上面给出了基本部分。下面的文档将介绍:
  • 定义app的核心框架组件。
  • 声明组件,为app请求设备特征的manifest文件。
  • 与代码分离,对不同设备配置能够使app最优的资源文件。

App Components

App组件是app中基本的行为模块。每个组件是一个不同的点,通过这个系统可以进入你的app。对用户来说,并不是每个组件都是真实的进入点,有一些组件依赖其他的组件,但是每一个作为自己的实体存在,扮演一个特殊的角色—-每个都是独一无二的行为模块,帮助定义app的整体行为。
有四种不同的组件。每种类型都有不同的目的,有创建和销毁组件的不同生命周期。
下面是四种app组件:
- Activity
一个activity表示一个可以用户交互的屏幕。比如说,一个email的app可能会有一个activity用来展示新邮件的列表,另一个activity用来写email,还有一个activity用来读email。虽然在这个email APP中这些activity一起工作形成了一个粘性的用户体验,但是每个相对其他来说都是独立的。这样,另一个app可以启动这些activity中的任意一个activity(这要这个email app允许)。比如说,用户为了分享图片,可以在一个camera的app中启动emial app中的写邮件的activity。
编写自己的activity作为activity的子类,关于这个可以参看developer guide中的activity。
- Service
Service是一个运行在后台的组件,用来执行耗时操作或者为remote进程执行操作。Service不提供UI。举例:当用户在另一个app中时,Service可以在后天播放音乐,或者可以在不阻塞用户交互的情况下,拉去网络数据。其他组件,比如一个activity,可以start service让他运行或者bind它来与它交互。
编写自己的Service要作为Service的子类,关于这个可以参看developr guide 的Service。
- Content providers
Content provider 管理一系列共享的app数据。你可以将数据存在文件系统中,SQLite数据库中,在web上,或者你的app可以访问的其他本地的持久化设备上。通过content provider,其他app可以查询甚至修改数据(如果content provider允许的话)。比如说,android 系统提供一个content provider来管理用户的联系人信息。这样,拥有适当权限的任何app可以查询content provider的一部分(比如说 ContactsContract.Data)来读取或者写特定人的信息。
Content providers对于app读写私有数据也非常有用。比如说,Note Pad的示例app使用content provider来保存笔记。
编写自己的Content provider要继承自ContentProvider,并且必须实现一些标准的API使得其他app可以执行事务。详细信息,可以看developer guide的ContentProviders.
- Broadcast receivers
广播接收是一个响应系统范围广播通知的组件。许多广播来源于系统–比如说,屏幕关闭、电池电量低或者捕获图片都会发送一个广播通知。app也可以初始化广播—–比如,让其他app知道一些数据已经下载到设备上,它们可以获取使用。虽然broadcast receivers,没有UI,但是它们可以创建一个状态栏通知当广播事件发生时提醒用户。通常,broadcast receivers都只是其他组件的网关,都只做很少的工作。举个例子,它可能基于这个事件来初始化一个service来执行一些工作。
自定义broadcast receivers继承BroadcastReceiver,每个broadcast 都作为intent对象发送。更多信息,可以看BroadcastReceiver类。
android系统设计的一个独特方面就是任何app可以启动另一个app的组件。比如说,如果你想让用户拍张照片,而这个功能可能另一个app中已经有了,而且你的app可以使用,那么你就可以直接使用而不是自己写一个拍照的activity。你不需要包含,或者说连接代码到有camera的app中。而是简单的启动camera app的activity来拍照。当完成时,照片甚至可以返回给你的app,你可以使用它。对于用户来说,好像拍照功能确实是你app的一部分。
当系统启动了一个组件,它就启动了那个app的进程(如果它还没运行的时候)并且实例化了那个组件的类。比如说,你的app启动了camera app的activity来拍照,那个拍照的activity属于camera app的进程,而不再你app的进程中。因此,不想其他系统的app,android 的app不是单点进入的(没有mian()方法)。
因为系统运行每一个app都在一个唯一的拥有权限文件的进程中,这样就限制了其他app的访问,你的app不能直接激活其他app中的组件。然而,android系统本身是可以的。所以,对于其他app中的组件,你必须发送一个消息给系统来指定你想启动的特定的组件。然后系统为你激活组件。

Activating Components

四个组件中的三个,activity、services、broadcast可以被称为intent的异步消息激活。无论组件是否属于自己的app,在运行时,intent绑定了独立的组件(可以认为是一个message,用于请求另一个组件action)。
intent是Intent的对象,它定义了一个消息用于激活指定的组件或者指定类型的组件—-或者说intent可以显式或者隐式使用。
对于activity和services,intent指定了要执行的action,也可能指定了处理数据的URI。举例:一个intent可能传递一个请求让activity来展示一张图片或者打开一个网页。有时候,你可以打开一个activity并要接收它的结果,在这种情况下,activity也要返回一个Intent类型的结果(举例,你可以发送一个intent让用户选择一个人的通讯录,然后将结果返回给你—-返回的intent中包含一个指向你选择通讯录人的URI)。
对于broadcast receivers,intent只是简单的定义了广播的通知(比如说,一个广播指示设备电量低,只包括一个指示电量低的已知action 字符串)。

intent 不能激活content provider组件。content provider需要ContentResolver激活。Content Resolver使用content provider处理所有的直接操作,所以组件不必使用provider执行操作,而是用ContentResolver对象的方法。这就为content provider和组件请求信息之间提供了一个抽象层(处于安全)。
激活不同的组件有不同的方法:

  • 可以传递Intent给startActivity()或者startActivityForResult()(当希望activity返回结果时)来启动activity。
  • 可以传递一个Intent给startService()来启动一个Service(或者给一个新的指令给正在运行的service)。或者可以将Intent给bindService()来绑定service。
  • 可以传递Intent给sendBroadcast()、sendOrderedBroadcast()或者sendStrickyBroadcast()来初始化broadcast。
  • 可以通过ContentResolver调用query()来执行content provider的查询操作。
    更多关于使用intent的信息,看Intents and Intent Filters文档。更多关于启动组件的信息请看:Activity,Services,BroadcastReceiver ,Content Providers文档。

The Manifest File

在android系统开始启动一个app的组件之前,系统必须通过读app的AndroidManifest.xml文件来知道组件存在。你的app必须在这个文件中声明它的所有组件,这个文件必须在项目的根目录下。
manifest中除了声明组件外,还要做一些事,例如:
- 识别app请求的所有用户权限,比如说访问网络或者读用户通讯录。
- 根据app使用的API,声明app要求的最小API Level。
- 声明app要求的硬件和软件特征,比如说照相机、蓝牙服务、多点触屏。
- app需要连接的API库(不是android frameWork APIs),比如说Google Maps Library。
- 等等

Declaring components

manifest的主要任务是告知系统关于app组件的信息。举例:manifest文件声明activity如下

<?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> 元素里面,android:icon属性指向一个icon的资源,用于表示这个app。
<activity>元素里面,android:name是指向Activity的子类的完全限定名。android:label属性位activity指定一个字符串作为用户可见的标签。
你必须用这种方式声明app的所有组件:

  • <activity> 为activity
  • <service> 为services
  • <receiver> 为 broadcast receivers
  • <provider> 为content provider
    在源文件中写的Activity,Service,Content provider,如果不在manifest文件中声明,系统是不可见的,因此,无法运行。然而,broadcast receivers可以在manifest中静态声明,也可以在代码中动态创建,并调用registerReceiver()在系统注册。
    更多关于怎样构建app的manifest文件的知识,请参看The AndroidManifest.xml File文档。

Declaring component capabilities

正如上面讨论的,可以使用intent来启动activity、service和broadcast receivers。你可以通过显式的指定目标组件的名字(组件的类名)来完成。然而,intent真正的威力在于隐式intent的概念。一个隐式的intent只需要声明要执行action的类型,允许系统在设备上找一个组件来执行action并启动它。如果有多个组件可以执行这个intent的action,由用户选择一个使用。
系统识别可以响应Intent的组件的方式是:将接收到的intent与设备上其他app的manifest文件中intent filter进行比较。
当你在app的manifest文件中声明activity时,你最好包括intent filter,它们声明了响应其他app的intent的能力。你可以通过给你的组件添加元素来给你的组件声明intent filter。
举例:如果你在写一个Email的app,其中一个activity是用来写邮件的,你可以为它声明一个intent filter来响应 “send”的intent(想要发新邮件),像这样:

<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>

那么,如果其他app创建一个有ACTION_SEND action的intent,然后传给startActivity(),系统可能会启动这个activity,所以用户可以写和发邮件。
关于更多创建intent filter的资料,请看Intents and Intent Filters 文档。

Declaring app requirements

android现在支持很多种设备,而它们并不能提供相同的特征和能力。为了防止你的app被安装到缺少你app所需特征的机器上,通过在manifest文件中清楚的声明app需要的设备和软件的条件很重要。大多数信息都只是报告,系统并不会读它们,但是其他机构比如说Google Play会读它们,当用户为他的设备搜索app时会进行过滤。
比如说,你的app需要一个camera,并使用Android2.1的API(API Level7),你应该这样在manifest中声明你的要求:

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

现在,如果设备没有camera或者Android版本低于2.1将不能在Google Play上安装你的app。
当然,你也可以声明你的app使用camera,但是不要求它。这样,你的app必须设置required属性为false,并且在运行时检查设备是否有camera,适当的禁止camera功能。
更多关于app兼容不同设备的信息,请查看Devive Compatibility文档。

App Resources

一个Android app不仅仅需要代码,它还需要资源,比如说图片,音频文件,还有其它与app视觉显示相关的文件。比如说,你应该定义动画、菜单、风格、颜色、activity的UI布局文件。使用app资源使得更新app的各种特征更加容易,不必修改代码,只是替换资源,使设备能够匹配不同的设备(你比如说语言,屏幕大小)。
你包含在Android 工程中的所有资源,SDK编译工具都定义了唯一的整型ID,这用这个id,你可以在你的代码中或者XML文件中引用资源。比如说,如果你的app中包含一个名为logo.png的图片(保存在res.drawable/directory中),SDK工具会生成一个名为R.drawable.logo的资源ID,你可以使用它引用这个图片,将他插在你的UI中。
将资源与源码分开一个最重要的方面是提供了一种根据不同配置的设备选择不同资源的能力。比如说,通过在XML中定义UI的字符串,你可以将这些字符串转变成其他语言或者将这些字符串保存在独立的文件中。然后,基于语言的限定,你可以在资源目录名下追加语言设置的名字(比如 res/values-fr/ 对于法语字符串)。Android系统应用适当的语言给你的UI。
Android系统为可选择的资源提供不同的限定符。限定符是一个短的字符串,包含在资源目录的名字中,如果要为不同的设备配置使用不同的资源的话,应该使用。再举个例子,你应该为你的activity创建不同的layout,依据屏幕的大小和方向。当设备屏幕是竖直放置时,你可能想要一个button是竖直方向的layout,而当屏幕是水平放置的时候,你可能想要一个button是水平方向的layout。为了根据方向变化layout,你可以定义两个不同的layout,给布局文件目录一个合适的限定名。然后,系统会根据党项设备的方向自动使用合适的布局。
关于应用中可以使用的资源种类和如何为不同设备创建可选择的资源的详细信息,请阅读Providing Resources.

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值