Android应用程序基础

http://developer.android.com/guide/components/fundamentals.html

应用程序基础

安卓app是用Java编程语言编写。安卓SDK工具把代码(包括任何数据和资源文件)编译成一个APK。APK(Android package)是一个以apk为后缀的压缩文件。一个APK文件包括一个安卓app的所有内容。安卓设备也是使用APK文件来安装app。

 

一旦安装到了设备,每个应用程序都存在于它自己的安全沙盒:

  •   安卓操作系统是多用户的Linux操作系统,每个app都有一个单独的用户。
  • 默认情况下,系统给每个应用程序分配一个唯一的用户ID(ID只由系统使用,对app透明)。系统给app内的所有文件设置权限,这样只有分配给这个app的用户ID才可以获取它们。
  •  每个进程都有它自己的虚拟机(VM),因此每个app的代码与其他app是独立运行的。
  •  默认情况下,每个app都是运行下它自己的Linux进程下。当一个app的组件需要执行的时候,安卓会启动一个进程,而当进程不再被需要或系统必须回收内存给其他app的时候,系统会关闭进程。 

通过这种方式,安卓系统遵从了最小特权原则。也就是,默认情况下,每个app只能获取到它工作时所需要的组件,仅此而已。这样创造了一个非常安全的环境,在这里面,一个app不能获取它没有权限的系统的部分。

 

然而,还是有一些方法可以让app与其他app进行数据共享,和获得系统服务:

  •   给两个app安排相同的Linux用户ID是可能的,这种情况下,它们能获取彼此的文件。为了节约系统资源,拥有相同用户ID的app可以运行在同一个Linux进程下并共享VM(这些app必须有相同的证书签名)。
  •  app可以请求获取设备数据,如用户联系人,SMS信息,可挂载的存储(SD卡),摄像头,蓝牙等。所有app权限都需要在安装时由用户授权。

 上面包括了一个安卓app存在于系统中需要注意的方面。这篇文档的其他部分还会向您介绍:

  • 定义app的核心框架组件。
  • 声明了app组件和app需要的设备特征的manifest文件。
  •  资源,与app代码分离,并可以为各种不同配置的设备进行优化。

App 组件

App组件是一个安卓app的关键构建块。每个组件都是不同的入口点,系统可以通过这些入口点来进入app。对用户来说不是所有的组件都是实际的入口点,一些依赖于其他的,但每一个都做为独立的入口而存在,并扮演着特定的角色,在定义app的整体形为上每个入口都是不同的构建块。

 

有四种不同的app组件类型。每种类型都有明确的目标,有明确的生存周期,并规定了组件如何创建和销毁。

 

这里就是四种app组件:

Activities

         activity表示用户界面中的一个单独的屏幕。例如,一个电子邮件app可能会有一个activity来显示新邮件的列表,另一个activity来写邮件,再有另一个activity来阅读邮件。在电子邮件app中,尽管是由这些activity一起工作来构成用户体验,但每一个都是独立的。也就是,一个不同的程序也可以启动这些activity中的任何一个(如果电子邮件app允许)。例如,一个摄像头app可以启动电子邮件app中的activity来写新邮件,这样用户可以分享图片。

一个activity是作为Activity(http://developer.android.com/reference/android/app/Activity.html)的子类来实现的,可以在Activities(http://developer.android.com/guide/components/activities.html)开发者指南里找到更多资料。

Services

         service是在后台运行长时间的操作的组件,也可以执行远程进行工作。一个service不提供用户界面。例如,当用户在使用一个app是地,一个service可以在后台播放音乐,或者在不阻塞用户与activity交互的情况下从网络获取数据。与activity一样,其他组件也可以启动service来使其运行,或者绑定到它,从而可以与其交互。

一个service是作为Service(http://developer.android.com/reference/android/app/Service.html)的子类来实现的,可以在Services(http://developer.android.com/guide/components/services.html)开发者指南里找到更多资料。

 Content providers

         contentprovider管理app数据的共享集。可以把这些数据存储于文件系统,SQLite数据库,网络上,或者app可以获取的其他的持久性存储位置。通过content provider,其他app可以查询甚至修改数据(如果content provider允许)。例如,安卓系统提供了一个content provider来管理用户联系人信息。所以,任何一个拥有相应权限的app都可以查询content provider部分(如ContactsContent.Data)来读取和写入特定的用户信息。

Content providers对于读取和写入app私有而不共享的数据也很有用。如Note Pad例子程序使用了content provider来保存笔记。

Content provider作为ContentProvider(http://developer.android.com/reference/android/content/ContentProvider.html)的子类实现,并且必须实现一个标准的API集来使其他app可以进行处理。更多的信息,可以参考Content Providers(http://developer.android.com/guide/topics/providers/content-providers.html)开发者指南。

 Broadcast receivers

          Broadcast receiver是应答系统级广播通知的组件。使用广播起源于系统,如这些广播通知,屏幕关闭、电量低、截图。App也可以初始化广播,如让其他app知道数据已经下载好并且可用了。尽管broadcast receiver不显示用户界面,但还是可以创建一个状态栏通知(http://developer.android.com/guide/topics/ui/notifiers/notifications.html)来通知用户一个广播事件发生了。然而更普遍的是,一个broadcast receiver只是作为一个相对其他组件的”网关”,并且只做很少量的工作。例如,可能是其他这个事件来初始化一个服务来执行一些工作。

Broadcast receiver是作为BroadcastReceiver(http://developer.android.com/reference/android/content/BroadcastReceiver.html)子类实现的,每个广播做为Intent(http://developer.android.com/reference/android/content/Intent.html)对象进行传递。更多信息,可以查看BroadcastRecevier(http://developer.android.com/reference/android/content/BroadcastReceiver.html)类。

安卓系统设计的一个独特方面是,任何一个app都可以启动其他应用的组件。例如,如何你想让用户使用设备的摄像头来获取一张图片,可能有另外一个app已经可以这么做了,这样你的app就可以直接使用它了,而不用自己来开发一个activity来获取图片。你不需要组合摄像头的代码,甚至不需要链接到摄像头的代码。你只需要启动能捕获图片的摄像头的app的activity就可以。捕获完后,图片返回到你的app然后就可以使用它了。对用户来说,就好像摄像头是你的app中的一部分一样。

 

当系统启动一个组件,会启动这个app的进程(如果没有在运行的话),并且实例化组件所需要的类。例如,如果你的app启动了摄像头app的activity来捕获图片,而这个activity是运行在摄像头app所在的进程,而不是你的app的进程。因此,不像大多数系统中的app,安卓app不是仅有单一的入口(例如,没有main()函数)。

 

由于系统是在独立的进行运行每个app,而进程的文件权限又限定了其他app的访问权限,你的app不能直接启动其他app中的组件。但安卓可以。所以,为了启动其他app中的组件,你必须给系统传递一个消息,来指明你的intent需要启动一个指定的组件。然后系统为你来启动指定的组件。

激活组件

四种组件中的三种:activity、service和broadcast receiver,由一种称为intent的异步消息来激活。Intent在运行时绑定不同的组件,可以把其想像成来来自另一个组件要求执行一个动作的使者,不管这个组件中属于你的app还是其他人的。

 

一个intent是在一个Intent(http://developer.android.com/reference/android/content/Intent.html)对象中被创建,这个对象定义了一个消息,来激活一个指定的组件或者是某类型的组件。因此,相对的,一个intent可以是明确的也可以是隐含的。

 

对activity和service来说,一个intent定义一需要执行的操作(如,“查看”或“发送”什么东西),并可能指明了需要操作的数据的URI(包括启动组件需要知晓的其他东西)。例如,一个intent可能传达了这样一个需求,需要一个activity来显示一个图片,或者打开一个网页。一些情况下,你可以启动了一个activity来接收结果,这种情况下,这个activity也会以Intent的形式来返回这个结果(例如,你可以发起一个intent来使用户选择一个联系人并把结果返回给你,返回的intent包含了指向选择的联系人的URI)。

 

对broadcast recevier,intent只是简单地定义了要广播的公告(例如,表示设备电量低的广播,只包含一个众所周知的字符串来表示“电量低”)。

 

另一种组件,content provider,不是由intent激活。而是当符合来自ContentResolver的请求时被激活。Content resolver通过content provider来处理所有的直接请求,因此通过provider来执行请求的组件,不需要,而是调用ContentResolver对象的方法。这样在content provider和需要信息的组件中留下了一个抽象层。

 

不同类型的组件有不同的激活方法:

  • 你可以给startActivity()传递一个Intent来启动一个activity(或者让其做一些新的工作),也可以调用startActivityForResult()(当你需要这个activity返回结果的时候)。
  • 你可以给startService()传递一个Intent来启动一个service(或者给正在运行的service以新指令)。也可以通过传递Intent给bindService()来绑定service。
  • 你可以把Intent传递给sendBroadcast(),sendOrderedBroadcast(),或者sendStickyBroadcast()来初始化一个广播。
  • 你可以在ContentResolver上调用query()来启动contentprovider上的查询。

使用intent的更多信息,参考Intents and intent Filters(http://developer.android.com/guide/components/intents-filters.html)文档。下列文档也提供了激活指定组件的信息:Activities,Services,BroadcastReceiver,Content Providers。

 

Manifest文件

在安卓系统可以启动app组件之前,系统需要通过查看app的AndroidManifest.xml文件来知晓存在的组件。你的app必须在这个文件中声明所有的组件,这个文件也必须在app工程的根目录。

 

Manifest文件除了声明app的组件外,还有其他一些工作,如:

  • 确认app需要的用户权限,如网络权限或读取用户联系人。
  • 声明app需要的最低的APILevel,app使用的是基本哪个API。
  • 声明app使用或需要的硬件和软件特征,如摄像头,蓝牙,或多点触控屏。
  • App需要链接到的API库(除了Android framework API外),如Google Maps library。
  •  其他。

声明组件

Manifest的主要作用是向系统声明app的组件。例如,一个manifest文件可以像如下声明一个activity:

<?xmlversion="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属性指向标识app的图标资源。

在<activity>元素中,android:name属性指明了Activity子类的完整的类名,android:label属性指明这个activity对于用户可见的字串。

你必须按这种方式声明所有的组件:

  • <activity>:activities
  • <service>:services
  • <receiver>:broadcast receivers
  • <provider>:content providers

 那些没有在manifest文件中声明却又在代码中的Activities,services,content providers,对系统来说是不可见的,必然的,也绝不会运行。然而,broadcast receivers即可以不在manifest中声明,也可以在代码中动态生成(如BroadcastReceiver对象)并用registerReceiver()向系统注册。

更多的如何组织app文件的manifest文件,查看The AndroidManifest.xml File(http://developer.android.com/guide/topics/manifest/manifest-intro.html)文档。

 

声明组件功能

如上面说明的,可以使用Intent来启动activities,services,broadcast receivers。你可以在intent中明确指明(使用组件的类名)目标组件。然而,intent的真正的实力在于隐匿的intent。隐匿的intent只是简单地描述要执行的动作的类型(可选的,也可以带上要执行的动作的相应数据),让系统找到能执行这个动作的组件并启动它。如果有多个组件能执行intent所描述的动作,由用户选择一个来执行。

系统把接收到的intent与设备中其他app的manifest文件中的intent filters进行比较,来确定对应于intent的组件。

当你在app中声明一个activity的时候,你可以加上声明这个activity功能的intent filter,这样它就可以响应来自其他app的intent。你可以通过向组件声明元素添加<intent-filter>子元素来声明你的组件的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动作创建了一个intent,并把其传递给了startActivity(),系统就可能启动你的activity,这样用户就可以编写和发送邮件。

更多关于intent filters的信息,参考Intents and Intent Filters(http://developer.android.com/guide/components/intents-filters.html)文档。

声明app的需求

Android支持各种设备,并不是所有的设备都提供了相同的特性和功能。为了避免把你的app安装到不具备app所需要的功能的设备上,有必要通过在manifest文件中声明所需要的设备和软件功能来明确的指明你的app所支持的设备类型。大多数这些声明只是些信息,系统不会去读取,但外部的服务如Google Play会读取它们,这样当用户在其设备中搜索app时可以为用户提供过滤功能。

例如,如果你的app要求有摄像头并使用了Android2.1中引入的API,你需要像这样在你的manifest文件中声明:

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

这样,没有摄像头或Android版本低于2.1的设备就不能从Google Play安装你的应用。

然而,你也可能声明你的app使用了摄像头,但并不需要它。这种情况下,app必须把required属性设置成false,并且在运行时检查设备是否有摄像头,相应的把摄像头相应的功能禁用。

更多的关于管理app与不同设备的兼容性的信息在Device Compatibility(http://developer.android.com/guide/practices/compatibility.html)文档。

 

App 资源

一个android app不只由代码构成,还需要与代码分离的资源,如图片,音频文件,和其他一切与app的可视表征有关的东西。例如,你应该用xml文件定义动画,菜单,类型,颜色和用户界面的排布。使用资源,可以很方便地在不修改代码的情况下升级app的各种特性(提供另一系列的资源),可以为不同的配置的设备优化app(如不同的语言和屏幕大小)。

对每一个包含进android工程中的资源,SDK构建工作为其定义了唯一的整型ID,通过这个ID可以在app代码或其他xml中定义的资源中引用这个资源。例如,如果你的app包含一个名称为logo.png的图片文件(保存在res/drawable目录),SDK工具产生一个叫R.drawable.logo的资源ID,你可以通过它引用这个图片,并把它插入到你的用户界面。

把资源从代码中分离出来的一个重要的方面是,你可以为不同配置的设备提供不同的资源。例如,通过在XML中定义UI字符串,你可以把字符串翻译成其他语言并把这些这符串保存在不同的文件中。然后,基于追加到资源目录名称后面(如法语字符串res/values-fr/)语言限定符和用户的语言设定,android会为你的ui加载正确的语言字符。

Android 为您替代资源支持许多不同的限定符。限定符是一个短的字符串,你包括你的资源目录的名称,以便定义这些资源应该用于该设备的配置。作为另一个例子,您应该经常为您的activity,根据设备的屏幕方向和大小创建不同的布局。例如,在设备屏幕纵向方向(高) 时,您可能希望一个布局,其中按钮是垂直的,但当屏幕在横向方向(宽),应水平对齐按钮。若要根据方向更改布局,可以定义两个不同的布局并将适当的限定符应用于每个布局的目录名称。然后,系统会自动将应用根据当前设备方向适当的布局。

关于可以包含在app中的不同的资源及如何为不同的配置的设备创建不同的资源的更多信息,查看Providing Resources(http://developer.android.com/guide/topics/resources/providing-resources.html)。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值