首页资源分类电子电路数字电路 > android手册

android手册

已有 445117个资源

下载专区

电子电路热门资源

本周本月全部

文档信息举报收藏

标    签:Android入门

分    享:

文档简介

Android开发,入门,经典,永恒

文档预览

Android 开发之旅——完整版 目录  Android 开发之旅:环境搭建及 HelloWorld  Android 开发之旅:HelloWorld 项目的目录结构  Android 开发之旅:android 架构  Android 开发之旅:应用程序基础及组件  Android 开发之旅:应用程序基础及组件(续)  Android 开发之旅:活动与任务  Android 开发之旅:进程与线程  Android 开发之旅:组件生命周期(一)  Android 开发之旅:组件生命周期(二)  Android 开发之旅:组件生命周期(三)  Android 开发之旅:又见 Hello World!  Android 开发之旅:深入分析布局文件&又是"Hello World!"  Android 开发之旅:view 的几种布局方式及实践  Android 开发之旅:短信的收发及在 android 模拟器之间实践(一)  Android 开发之旅:短信的收发及在 android 模拟器之间实践(二)  Android 开发之旅: Intents 和 Intent Filters(理论部分) Android 开发之旅:环境搭建及 HelloWorld ——工欲善其事必先利其器 引言 本系列适合 0 基础的人员,因为我就是从 0 开始的,此系列记录我步入 Android 开发的一些经验分享, 望与君共勉!作为 Android 队伍中的一个新人的我,如果有什么不对的地方,还望不吝赐教。 在开始 Android 开发之旅启动之前,首先要搭建环境,然后创建一个简单的 HelloWorld。本文的主题 如下:  1、环境搭建 o 1.1、JDK 安装 o 1.2、Eclipse 安装 o 1.3、Android SDK 安装 o 1.4、ADT 安装 o 1.5、创建 AVD  2、HelloWorld 1、环境搭建 1.1、JDK 安装 如果你还没有 JDK 的话,可以去这里下载,接下来的工作就是安装提示一步一步走。设置环境变量步 骤如下: 1. 我的电脑->属性->高级->环境变量->系统变量中添加以下环境变量: 2. JAVA_HOME 值为: D:\Program Files\Java\jdk1.6.0_18(你安装 JDK 的目录) 3. CLASSPATH 值 为:.;%JAVA_HOME%\lib\tools.jar;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\bin; 4. Path: 在开始追加 %JAVA_HOME%\bin; 5. NOTE:前面四步设置环境变量对搭建 Android 开发环境不是必须的,可以跳过。 安装完成之后,可以在检查 JDK 是否安装成功。打开 cmd 窗口,输入 java –version 查看 JDK 的版本 信息。出现类似下面的画面表示安装成功了: 图 1、验证 JDK 安装是否成功 1.2、Eclipse 安装 如果你还么有 Eclipse 的话,可以去这里下载,下载如下图所示的 Eclipse IDE for Java Developers (92M)的 win 32bit 版: 图 2、Eclipse 下载 解压之后即可使用。 1.3、Android SDK 安装 在 Android Developers 下载 android-sdk_r05-windows.zip,下载完成后解压到任意路径。  运行 SDK Setup.exe,点击 Available Packages。如果没有出现可安装的包,请点击 Settings, 选中 Misc 中的"Force https://..."这项,再点击 Available Packages 。  选择希望安装的 SDK 及其文档或者其它包,点击 Installation Selected、Accept All、Install Accepted,开始下载安装所选包  在用户变量中新建 PATH 值为:Android SDK 中的 tools 绝对路径(本机为 D:\AndroidDevelop\android-sdk-windows\tools)。 图 2、设置 Android SDK 的环境变量 ―确定‖后,重新启动计算机。重启计算机以后,进入 cmd 命令窗口,检查 SDK 是不是安装成功。 运行 android –h 如果有类似以下的输出,表明安装成功: 图 3、验 证 Android SDK 是否安装成功 1.4、ADT 安装  打开 Eclipse IDE,进入菜单中的 "Help" -> "Install New Software"  点击 Add...按钮,弹出对话框要求输入 Name 和 Location:Name 自己随便取,Location 输入 http://dl-ssl.google.com/android/eclipse。如下图所示:  确定返回后,在 work with 后的下拉列表中选择我们刚才添加的 ADT,我们会看到下面出有 Developer Tools,展开它会有 Android DDMS 和 Android Development Tool,勾选他们。 如下图所 示:  然后就是按提示一步一步 next。 完成之后:  选择 Window > Preferences...  在左边的面板选择 Android,然后在右侧点击 Browse...并选中 SDK 路径,本机为: D:\AndroidDevelop\android-sdk-windows  点击 Apply、OK。配置完成。 1.5、创建 AVD 为使 Android 应用程序可以在模拟器上运行,必须创建 AVD。  1、在 Eclipse 中。选择 Windows > Android SDK and AVD Manager  2、点击左侧面板的 Virtual Devices,再右侧点击 New  3、填入 Name,选择 Target 的 API,SD Card 大小任意,Skin 随便选,Hardware 目前保持默 认值  4、点击 Create AVD 即可完成创建 AVD 注意:如果你点击左侧面板的 Virtual Devices,再右侧点击 New ,而 target 下拉列表没有可选项时, 这时候你:  点击左侧面板的 Available Packages,在右侧勾选 https://dl-ssl.google.com/android/repository/repository.xml,如下图所示: o 然后点击 Install Selected 按钮,接下来就是按提示做就行了 要做这两步,原因是在 1.3、Android SDK 安装中没有安装一些必要的可用包(Available Packages)。 2、HelloWorld  通过 File -> New -> Project 菜单,建立新项目"Android Project"  然后填写必要的参数,如下图所示:(注意这里我勾选的是 Google APIs,你可以选你喜欢的, 但你要创建相应的 AVD) 相关参数的说明: 1. Project Name: 包含这个项目的文件夹的名称。 2. Package Name: 包名,遵循 JAVA 规范,用包名来区分不同的类是很重要的,我用 的是 helloworld.test。 3. Activity Name: 这是项目的主类名,这个类将会是 Android 的 Activity 类的子类。 一个 Activity 类是一个简单的启动程序和控制程序的类。它可以根据需要创建界面, 但不是必须的。 4. Application Name: 一个易读的标题在你的应用程序上。 5. 在"选择栏"的 "Use default location" 选项,允许你选择一个已存在的项目。  点击 Finish 后,点击 Eclipse 的 Run 菜单选择 Run Configurations…  选择―Android Application‖,点击在左上角(按钮像一张纸上有个―+‖号)或者双击―Android Application‖, 有个新的选项―New_configuration‖(可以改为我们喜欢的名字)。  在右侧 Android 面板中点击 Browse…,选择 HelloWorld  在 Target 面板的 Automatic 中勾选相应的 AVD,如果没有可用的 AVD 的话,你需要点击右 下角的 Manager…,然后新建相应的 AVD。如下图所示:  然后点 Run 按钮即可,运行成功的话会有 Android 的模拟器界面,如下图所示: 引言 前面 Android 开发之旅:环境搭建及 HelloWorld,我们介绍了如何搭建 Android 开发环境及简单地建 立一个 HelloWorld 项目,本篇将通过 HelloWorld 项目来介绍 Android 项目的目录结构。本文的主要 主题如下:  1、HelloWorld 项目的目录结构 o 1.1、src 文件夹 o 1.2、gen 文件夹 o 1.3、Android 2.1 文件夹 o 1.4、assets o 1.5、res 文件夹 o 1.6、AndroidManifest.xml o 1.7、default.properties 1、HelloWorld 项目的目录结构 (这个 HelloWorld 项目是基于 Android 2.1 的)在 Eclipse 的左侧展开 HelloWorld 项目,可以看到如 下图的目录结构: 图 1、HelloWorld 项目目录结 构 下面将分节介绍上面的各级目录结构。 1.1、src 文件夹 顾名思义(src, source code)该文件夹是放项目的源代码的。打开 HelloWorld.java 文件会看到如下代 码: HelloWorld.java 可以知道:我们新建一个简单的 HelloWorld 项目,系统为我们生成了一个 HelloWorld.java 文件。他 导入了两个类 android.app.Activity 和 android.os.Bundle,HelloWorld 类继承自 Activity 且重写了 onCreate 方法。 以下说明针对没有学过 Java 或者 Java 基础薄弱的人 @Override 在重写父类的 onCreate 时,在方法前面加上@Override 系统可以帮你检查方法的正确性。例如,public void onCreate(Bundle savedInstanceState){…….}这种写法是正确的,如果你写成 public void oncreate(Bundle savedInstanceState){…….}这样编译器回报如下错误——The method oncreate(Bundle) of type HelloWorld must override or implement a supertype method,以确保你正确重写 onCreate 方法。(因为 oncreate 应该 为 onCreate) 而如果你不加@Override,则编译器将不会检测出错误,而是会认为你新定义了一个方法 oncreate。 android.app.Activity 类:因为几乎所有的活动(activities)都是与用户交互的,所以 Activity 类关注 创建窗口,你可以用方法 setContentView(View)将自己的 UI 放到里面。然而活动通常以全屏的方 式展示给用户,也可以以浮动窗口或嵌入在另外一个活动中。有两个方法是几乎所有的 Activity 子类都 实现的: 1. onCreate(Bundle):初始化你的活动(Activity),比如完成一些图形的绘制。最 重要的是,在这个方法里你通常将用布局资源(layout resource)调用 setContentView(int)方法定义你的 UI,和用 findViewById(int)在你的 UI 中检索你 需要编程地交互的小部件(widgets)。setContentView 指定由哪个文件指定布局 (main.xml),可以将这个界面显示出来,然后我们进行相关操作,我们的操作会被 包装成为一个意图,然后这个意图对应有相关的 activity 进行处理。 2. onPause():处理当离开你的活动时要做的事情。最重要的是,用户做的所有改变应该在这里 提交(通常 ContentProvider 保存数据)。 更多的关于 Activity 类的详细信息此系列以后的文章将做介绍,如果你想了解更多请参阅相关文档。 android.os.Bundle 类:从字符串值映射各种可打包的(Parcelable)类型(Bundle 单词就是捆绑的意 思,所有这个类很好理解和记忆)。如该类提供了公有方法——public boolean containKey(String key), 如果给定的 key 包含在 Bundle 的映射中返回 true,否则返回 false。该类实现了 Parceable 和 Cloneable 接口,所以它具有这两者的特性。 1.2、gen 文件夹 该文件夹下面有个 R.java 文件,R.java 是在建立项目时自动生成的,这个文件是只读模式的,不能更 改。R.java 文件中定义了一个类——R,R 类中包含很多静态类,且静态类的名字都与 res 中的一个名 字对应,即 R 类定义该项目所有资源的索引。看我们的 HelloWorld 项目是不是如此,如下图: 图 2、R.java 对应 res 通过 R.java 我们可以很快地查找我们需要的资源,另外编绎器也会检查 R.java 列表中的资源是否被 使用到,没有被使用到的资源不会编绎进软件中,这样可以减少应用在手机占用的空间。 1.3、Android 2.1 文件夹 该文件夹下包含 android.jar 文件,这是一个 Java 归档文件,其中包含构建应用程序所需的所有的 Android SDK 库(如 Views、Controls)和 APIs。通过 android.jar 将自己的应用程序绑定到 Android SDK 和 Android Emulator,这允许你使用所有 Android 的库和包,且使你的应用程序在适当的环境中 调试。例如上面的 HelloWorld.java 源文件中的: import android.app.Activity; import android.os.Bundle; 这里两行代码就是从 android.jar 导入包。 1.4、assets 包含应用系统需要使用到的诸如 mp3、视频类的文件。 1.5、res 文件夹 资源目录,包含你项目中的资源文件并将编译进应用程序。向此目录添加资源时,会被 R.java 自动记 录。新建一个项目,res 目录下会有三个子目录:drawabel、layout、values。  drawabel-?dpi:包含一些你的应用程序可以用的图标文件(*.png、*.jpg)  layout:界面布局文件(main.xml)与 WEB 应用中的 HTML 类同,没修改过的 main.xml 文件 如下(HelloWorld 的就没有修改过): main.xml  values:软件上所需要显示的各种文字。可以存放多个*.xml 文件,还可以存放不同类型的数据。 比如 arrays.xml、colors.xml、dimens.xml、styles.xml 1.6、AndroidManifest.xml 项目的总配置文件,记录应用中所使用的各种组件。这个文件列出了应用程序所提供的功能,在这个文 件中,你可以指定应用程序使用到的服务(如电话服务、互联网服务、短信服务、GPS 服务等等)。另外 当你新添加一个 Activity 的时候,也需要在这个文件中进行相应配置,只有配置好后,才能调用此 Activity。AndroidManifest.xml 将包含如下设置:application permissions、Activities、intent filters 等。 如果你跟我一样是 ASP.NET 出生或者学过,你会发现 AndroidManifest.xml 跟 web.config 文件很像,可以 把它类同于 web.config 文件理解。 如果你不是,你可以这样理解——众所周知 xml 是一种数据交换格式,AndroidManifest.xml 就是用来存储 一些数据的,只不过这些数据时关于 android 项目的配置数据。 HelloWorld 项目的 AndroidManifest.xml 如下所示: AndroidManifest.xml 关于 AndroidManifest.xml 现在就讲这么多,此系列后面的文章将单 独详细介绍。 1.7、default.properties 记录项目中所需要的环境信息,比如 Android 的版本等。 HelloWorld 的 default.properties 文件代码 如下所示,代码中的注释已经把 default.properties 解释得很清楚了: default.properties 引言 通过前面两篇:  Android 开发之旅:环境搭建及 HelloWorld  Android 开发之旅:HelloWorld 项目的目录结构 我们对 android 有了个大致的了解,知道如何搭建 android 的环境及简单地写一个 HelloWorld 程序, 而且知道一个 android 项目包括哪些文件夹和文件及相应的作用。本篇将站在顶级的高度——架构,来 看 android。我开篇就说了,这个系列适合 0 基础的人且我也是从 0 开始按照这个步骤来学的,谈架构 是不是有点螳臂挡车,自不量力呢?我觉得其实不然,如果一开始就对整个 android 的架构了然于胸, 就不会误入歧途,能够很好地把握全局。本文的主题如下:  1、架构图直观  2、架构详解 o 2.1、Linux Kernel o 2.1、Android Runtime o 2.3、Libraries o 2.4、Application Framework o 2.5、Applications  3、总结 1、架构图直观 下面这张图展示了 Android 系统的主要组成部分: 图 1、Android 系统架构(来源于:android sdk) 可以很明显看出,Android 系统架构由 5 部分组成,分别是:Linux Kernel、Android Runtime、Libraries、 Application Framework、Applications。第二部分将详细介绍这 5 个部分。 2、架构详解 现在我们拿起手术刀来剖析各个部分。其实这部分 SDK 文档已经帮我们做得很好了,我们要做的就是 拿来主义,然后再加上自己理解。下面自底向上分析各层。 2.1、Linux Kernel Android 基于 Linux 2.6 提供核心系统服务,例如:安全、内存管理、进程管理、网络堆栈、驱动模型。 Linux Kernel 也作为硬件和软件之间的抽象层,它隐藏具体硬件细节而为上层提供统一的服务。 如果你学过计算机网络知道 OSI/RM,就会知道分层的好处就是使用下层提供的服务而为上层提供统一 的服务,屏蔽本层及以下层的差异,当本层及以下层发生了变化不会影响到上层。也就是说各层各司其 职,各层提供固定的 SAP(Service Access Point),专业点可以说是高内聚、低耦合。 如果你只是做应用开发,就不需要深入了解 Linux Kernel 层。 2.2、Android Runtime Android 包含一个核心库的集合,提供大部分在 Java 编程语言核心类库中可用的功能。每一个 Android 应用程序是 Dalvik 虚拟机中的实例,运行在他们自己的进程中。Dalvik 虚拟机设计成,在一个设备可 以高效地运行多个虚拟机。Dalvik 虚拟机可执行文件格式是.dex,dex 格式是专为 Dalvik 设计的一种 压缩格式,适合内存和处理器速度有限的系统。 大多数虚拟机包括 JVM 都是基于栈的,而 Dalvik 虚拟机则是基于寄存器的。两种架构各有优劣,一般 而言,基于栈的机器需要更多指令,而基于寄存器的机器指令更大。dx 是一套工具,可以將 Java .class 转换成 .dex 格式。一个 dex 文件通常会有多个.class。由于 dex 有時必须进行最佳化,会使文件大小 增加 1-4 倍,以 ODEX 结尾。 Dalvik 虚拟机依赖于 Linux 内核提供基本功能,如线程和底层内存管理。 2.3、Libraries Android 包含一个 C/C++库的集合,供 Android 系统的各个组件使用。这些功能通过 Android 的应用 程序框架(application framework)暴露给开发者。下面列出一些核心库:  系统 C 库——标准 C 系统库(libc)的 BSD 衍生,调整为基于嵌入式 Linux 设备  媒体库——基于 PacketVideo 的 OpenCORE。这些库支持播放和录制许多流行的音频和视频格 式,以及静态图像文件,包括 MPEG4、 H.264、 MP3、 AAC、 AMR、JPG、 PNG  界面管理——管理访问显示子系统和无缝组合多个应用程序的二维和三维图形层  LibWebCore——新式的 Web 浏览器引擎,驱动 Android 浏览器和内嵌的 web 视图  SGL——基本的 2D 图形引擎  3D 库——基于 OpenGL ES 1.0 APIs 的实现。库使用硬件 3D 加速或包含高度优化的 3D 软件光 栅  FreeType ——位图和矢量字体渲染  SQLite ——所有应用程序都可以使用的强大而轻量级的关系数据库引擎 2.4、Application Framework 通过提供开放的开发平台,Android 使开发者能够编制极其丰富和新颖的应用程序。开发者可以自由地 利用设备硬件优势、访问位置信息、运行后台服务、设置闹钟、向状态栏添加通知等等,很多很多。 开发者可以完全使用核心应用程序所使用的框架 APIs。应用程序的体系结构旨在简化组件的重用,任 何应用程序都能发布他的功能且任何其他应用程序可以使用这些功能(需要服从框架执行的安全限制)。 这一机制允许用户替换组件。 所有的应用程序其实是一组服务和系统,包括:  视图(View)——丰富的、可扩展的视图集合,可用于构建一个应用程序。包括包括列表、网 格、文本框、按钮,甚至是内嵌的网页浏览器  内容提供者(Content Providers)——使应用程序能访问其他应用程序(如通讯录)的数据, 或共享自己的数据  资源管理器(Resource Manager)——提供访问非代码资源,如本地化字符串、图形和布局 文件  通知管理器(Notification Manager)——使所有的应用程序能够在状态栏显示自定义警 告  活动管理器(Activity Manager)——管理应用程序生命周期,提供通用的导航回退功能 2.5、Applications Android 装配一个核心应用程序集合,包括电子邮件客户端、SMS 程序、日历、地图、浏览器、联系 人和其他设置。所有应用程序都是用 Java 编程语言写的。更加丰富的应用程序有待我们去开发! 3、总结 从上面我们知道 Android 的架构是分层的,非常清晰,分工很明确。Android 本身是一套软件堆叠 (Software Stack),或称为「软件叠层架构」,叠层主要分成三层:操作系统、中间件、应用程序。从 上面我们也看到了开源的力量,一个个熟悉的开源软件在这里贡献了自己的一份力量。 现在我们对 android 的系统架构有了一个整体上的了解,我将用一个例子来深入体会一下,但是考虑到 此系列希望 0 基础的人也能看懂,在介绍例子之前将介绍一下 Android 应用程序的原理及一些术语, 可能需要几篇来介绍。敬请关注! ——成功属于耐得住寂寞的人,接下来几篇将讲述 Android 应用程序的原理及术语,可能 会比较枯燥。如果能够静下心来看,相信成功将属于你。 引言 为了后面的例子做准备,本篇及接下来几篇将介绍 Android 应用程序的原理及术语,这些也是作为一 个 Android 的开发人员必须要了解,且深刻理解的东西。本篇的主题如下:  1、应用程序基础  2、应用程序组件 o 2.1、活动(Activities) o 2.2、服务(Services) o 2.3、广播接收者(Broadcast receivers) o 2.4、内容提供者(Content providers) 因为这些内容比较理论,且没有用例子来说明,看上去会比较枯燥,我就把这几篇写得算比较短,方便 大家吸收。 1、应用程序基础 Android 应用程序是用 Java 编程语言写的。编译后的 Java 代码——包括应用程序要求的任何数据和资 源文件,通过 aapt 工具捆绑成一个 Android 包,归档文件以.apk 为后缀。这个文件是分发应用程序和 安装到移动设备的中介或工具,用户下载这个文件到他们的设备上。一个.apk 文件中的所有代码被认 为是一个应用程序。 aapt: aapt 是 Android Asset Packaging Tool 的首字母缩写,这个工具包含在 SDK 的 tools/目录下。查看、创建、 更新与 zip 兼容的归档文件(zip、jar、apk)。它也能将资源文件编译成二进制包。 尽管你可能不会经常直接使用 appt,但是构建脚本(build scripts)和 IDE 插件会使用这个工具打包 apk 文 件,构成一个 Android 应用程序。 如需更详细的使用细节,打开一个终端,进入 tools/目录下,运行命令:  Linux 或 Mac 操作系统:./aapt  Windows:aapt.exe 注意:tools/目录是指 android SDK 目录下的/platforms/android-X/tools/ 在许多方面,每个 Android 应用程序生活在它自己的世界:  默认情况下,每一个应用程序运行在它自己的 Linux 进程中。当应用程序中的任何代码需要执 行时,Android 将启动进程;当它不在需要和系统资源被其他应用程序请求时,Android 将关闭进程。  每个应用程序都有他自己的 Java 虚拟机(VM),因此应用程序代码独立于其他所有应用程序 的代码运行。  默认情况下,每个应用程序分配一个唯一的 Linux 用户的 ID。权限设置为每个应用程序的文件 仅对用户和应用程序本身可见——虽然也有一些方法可以暴露他们给其他应用程序。 有可能设置两个应用程序共享一个用户 ID,这种情况下,他们能够看到对方的文件。为了节省系统资 源,具有相同 ID 的应用程序也可以安排在同一个 Linux 进程中,共享同一个 VM。 2、应用程序组件 Android 的一个主要特点是,一个应用程序可以利用其他应用程序的元素(假设这些应用程序允许的 话)。例如,如果你的应用程序需要显示一个图像的滚动列表,且其他应用程序已经开发了一个合适的 滚动条并可以提供给别的应用程序用,你可以调用这个滚动条来工作,而不用自己开发一个。你的应用 程序不用并入其他应用程序的代码或链接到它。相反,当需求产生时它只是启动其他应用程序块。 对于这个工作,当应用程序的任何部分被请求时,系统必须能够启动一个应用程序的进程,并实例化该 部分的 Java 对象。因此,不像其他大多数系统的应用程序,Android 应用程序没有一个单一的入口点 (例如,没有 main()函数)。相反,系统能够实例化和运行需要几个必要的组件。有四种类型的组件: 1. 活动(Activities) 2. 服务(Services) 3. 广播接收者(Broadcast receivers) 4. 内容提供者(Content providers) 然而,并不是所有的应用程序都必须包含上面的四个部分,你的应用程序可以由上面的一个或几个来组 建。当你决定使用以上哪些组件来构建 Android 应用程序时,你应该将它们列在 AndroidManifest.xml 文件中,在这个文件中你可以声明应用程序组件以及它们的特性和要求。关于 AndroidManifest.xml 在 Android 开发之旅:HelloWorld 项目的目录结构的 1.6、AndroidManifest.xml 简单介绍了一下,你 可以参考一下,下篇也将介绍它。 2.1、活动(Activities) 一个活动表示一个可视化的用户界面,关注一个用户从事的事件。例如,一个活动可能表示一个用户可 选择的菜单项列表,或者可能显示照片连同它的标题。一个文本短信应用程序可能有一个活动,显示联 系人的名单发送信息;第二个活动,写信息给选定的联系人;其他活动,重新查看旧信息或更改设置。 虽然他们一起工作形成一个整体的用户界面,但是每个活动是独立于其他活动的。每一个都是作为 Activity 基类的一个子类的实现。 android.app.Activity 类:因为几乎所有的活动(activities)都是与用户交互的,所以 Activity 类关注创建窗 口,你可以用方法 setContentView(View)将自己的 UI 放到里面。然而活动通常以全屏的方式展示给用 户,也可以以浮动窗口或嵌入在另外一个活动中。有两个方法是几乎所有的 Activity 子类都实现的: 1. onCreate(Bundle):初始化你的活动(Activity),比如完成一些图形的绘制。最 重要的是,在这个方法里你通常将用布局资源(layout resource)调用 setContentView(int)方法定义你的 UI,和用 findViewById(int)在你的 UI 中检索你 需要编程地交互的小部件(widgets)。setContentView 指定由哪个文件指定布局 (main.xml),可以将这个界面显示出来,然后我们进行相关操作,我们的操作会被 包装成为一个意图(Intent),然后这个意图对应有相关的 activity 进行处理。 2. onPause():处理当离开你的活动时要做的事情。最重要的是,用户做的所有改变应该在这里提交 (通常 ContentProvider 保存数据)。 一个应用程序可能只包含一个活动,或者像刚才提到的短信应用,它可能包含几个活动。这些活动是什 么,以及有多少,当然这取决于它的应用和设计。一般来讲,当应用程序被启动时,被标记为第一个的 活动应该展示给用户。从一个活动移动到另一个活动由当前的活动完成开始下一个。 每一个活动都有一个默认的窗口。一般来讲,窗口会填满整个屏幕,但是它可能比屏幕小或浮在其他窗 口上。一个活动还可以使用额外的窗口——例如弹出式对话框,或当一用户选择屏幕上一个特定的项时 一个窗口显示给用户重要的信息。 窗口的可视内容是由继承自 View 基类的一个分层的视图—对象提供。每个视图控件是窗口内的一个特 定的矩形空间。父视图包含和组织子女视图的布局。叶子视图(在分层的底层)绘制的矩形直接控制和 响应用户的操作。因此,一个视图是活动与用户交互发生的地方。例如,一个视图可能显示一个小的图 片和当用户点击图片时发起一个行为。Android 有一些现成的视图你可以使用,包括按钮(buttons)、 文本域(text fields)、滚动条(scroll bars)、菜单项(menu items)、复选框(check boxes)等等。 通过 Activity.setContentView() 方法放置一个视图层次在一个活动窗口中。内容视图(content view) 是层次结构的根视图对象。层次结构如下图所示: 图 1、视图的层次结构 Activity.setContentView() 方法: public void setContentView (int layoutResID):根据布局资源设置活动的界面。 资源将被夸大,添加布局资源文件中 所有的最高层的视图( top-level views )到活动. 2.2、 服务(Services) 一个服务没有一个可视化用户界面,而是在后台无期限地运行。例如一个服务可能是播放背景音乐而用 户做其他一些事情,或者它可能从网络获取数据,或计算一些东西并提供结果给需要的活动(activities)。 每个服务都继承自 Service 基类。 每个服务类在 AndroidManifest.xml 中有相应的声明。服务可以通过 Context.startService()和 Context.bindService()启动。 一个典型的例子是一个媒体播放器播放一个播放列表中的歌曲。该播放器应用程序将可能有一个或多个 活动(activities),允许用户选择歌曲和开始播放。然而,音乐播放本身不会被一个活动处理,因为用 户希望保持音乐继续播放,当用户离开播放器去做其他事情时。为了保持音乐继续播放,媒体播放器活 动可以启动一个服务运行在后台。系统将保持音乐播放服务运行,甚至媒体播放器离开屏幕时。 可以连接到(绑定到)一个持续运行的服务(并启动服务,如果它尚未运行)。连接之后,你可以通过 服务暴露的接口与服务交流。对于音乐服务,这个接口可以允许用户暂停、倒带、停止和重新播放。 像活动(activities)和其他组件一样,服务(services)运行在应用程序进程中的主线程中。因此,他 们将不会阻止其他组件或用户界面,他们往往产生其他一些耗时的任务(如音乐播放)。 2.3、广播接收者(Broadcast receivers) 一个广播接收者是这样一个组件,它不做什么事,仅是接受广播公告并作出相应的反应。许多广播源自 于系统代码,例如公告时区的改变、电池电量低、已采取图片、用户改变了语言偏好。应用程序也可以 发起广播,例如为了他其他程序知道某些数据已经下载到设备且他们可以使用这些数据。 一个应用程序可以有任意数量的广播接收者去反应任何它认为重要的公告。所有的接受者继承自 BroadcastReceiver 基类。 BroadcastReceiver 类: 是接受 sendBroadcast()发送的意图(intents)的基类。可以用 Context.registerReceiver()动态地注册这个 类的实例,或者通过 AndroidManifest.xml 中标签静态发布。注意:如果你在 Activity.onResume() 注册一个接受者,你应该在 Activity.onPause()注销它。因为当暂停时你不会收 到意图,注销它将削减不必要的系统开销。不要在 Activity.onSaveInstanceState()中注销它,因为它将 不会被调用,如果用户移动到先前的堆栈。 有两种主要的可接受广播类型: 1. 正常广播(由 Context.sendBroadcast 发送)是完全异步的。所有的广播接收者以无序方式运行, 往往在同一时间接收。这样效率较高,但是意味着接受者不能使用结果或终止广播数据传播。 2. 有序广播(由 Context.sendOrderedBroadcast 发送)一次传递给一个接收者。由于每个接收者依次 执行,因此它可以传播到下一个接收器,也可以完全终止传播以便他不会传递给其他接收者。接收者 的运行顺序可由匹配的意图过滤器(intent-filter)的 android:priority 属性控制。 广播接收者不显示一个用户界面。然而,它们启动一个活动去响应收到的信息,或者他们可能使用 NotificationManager 去通知用户。通知可以使用多种方式获得用户的注意——闪烁的背光、振动设 备、播放声音等等。典型的是放在一个持久的图标在状态栏,用户可以打开获取信息。 2.4、内容提供者(Content providers) 内容提供者(content provider)使一个应用程序的指定数据集提供给其他应用程序。这些数据可以存 储在文件系统中、在一个 SQLite 数据库、或以任何其他合理的方式。内容提供者继承自 ContentProvider 基类并实现了一个标准的方法集,使得其他应用程序可以检索和存储数据。然而,应用程序并不直接调 用这些方法。相反,替代的是它们使用一个 ContentResolver 对象并调用它的方法。ContentResolver 能与任何内容提供者通信,它与提供者合作来管理参与进来的进程间的通信。 内容提供者是 Android 应用程序的主要组成部分之一,提供内容给应用程序。他们封装数据且通过单个 ContentResolver 接口提供给应用程序。只有需要在多个应用程序间共享数据是才需要内容提供者。例如, 通讯录数据被多个应用程序使用,且必须存储在一个内容提供者中。如果你不需要在多个应用程序间共享数 据,你可以直接使用 SQLiteDataBase。 当 ContentResolver 发出一个请求时,系统检查给定的 URI 的权限并传递请求给内容提供者注册。内容提供 者能理解 URI 想要的东西。UriMatcher 类用于帮组解析 URIs。 需要实现的方法主要如下:  query(Uri, String[], String, String[], String) 返回数据给调用者  insert(Uri, ContentValues) 插入数据到内容提供者  update(Uri, ContentValues, String, String[]) 更新内容提供者已存在的数据  delete(Uri, String, String[]) 从内容提供者中删除数据  getType(Uri) 返回内容提供者中的 MIME 类型数据 更多的关于 ContentResolver 信息,请查看相关文档。 每当有一个应该由特定组件处理的请求,Android 可以确保该组件的应用程序正在运行,如果没有就启 动它,而且一个适当的组件实例可用,如果没有就创建。 ——成功属于耐得住寂寞的人,你离成功又近了一步了。 引言 上篇 Android 开发之旅:应用程序基础及组件介绍了应用程序的基础知识及 Android 的四个组件,本 篇将介绍如何激活组关闭组件等。本文的主题如下:  1、激活组件:意图(Intents) o 1.1、活动(Activity)组件的激活 o 1.2、服务(Service)组件的激活 o 1.3、广播接收者(Broadcast receiver)组件的激活  2、关闭组件  3、清单文件  4、Intent 过滤器 1、激活组件:意图(Intents) 当接收到 ContentResolver 发出的请求后,内容提供者被激活。而其它三种组件——活动、服务和广播 接收者,被一种叫做意图(intent)的异步消息激活。意图是一个保存着消息内容的 Intent 对象。对 于活动和服务来说,Intent 对象指明了请求的操作名称以及作为操作对象的数据的 URI 和其它一些信 息。例如,它可以传递对活动的一个请求,让它为用户显示一张图片,或者让用户编辑一些文本。而对 于广播接收者而言,Intent 对象指明了广播的行为。例如当照相按钮被按下,它可以对所有感兴趣的对 象广播。 对于每种组件来说,激活的方法是不同的。下面将分别介绍活动、服务、广播接收者组件的激活方法。 1.1、活动(Activity)组件的激活 通过传递一个 Intent 对象至 Context.startActivity()或 Activity.startActivityForResult()以载入(或指定 新工作给)一个活动。相应的活动可以看到初始的意图,这个意图通过 getIntent() 方法来查看激活活 动。Android 调用活动的 onNewIntent()方法传递任何后续的意图。 一个活动经常启动了下一个。如果它期望它所启动的那个活动返回一个结果,它会调用 startActivityForResult()而不是 startActivity()。例如,如果它启动了一个活动让用户挑选一张照片,它 可能会返回被选中的照片。结果以一个 Intent 对象传递调用活动的 onActivityResult() 方法。 1.2、服务(Service)组件的激活 通过传递一个 Intent 对象至 Context.startService()以启动一个服务(或给予正在运行的服务以一个新 的指令)。Android 调用服务的 onStart()方法并将 Intent 对象传递给它。 与此类似,一个 Intent 可以传递给 Context.bindService()以在调用的组件和目标服务之间建立持续的 连接。这个服务会在调用 onBind() 方法中接受这个 Intent 对象(如果服务尚未启动,bindService() 会先启动它)。例如,一个活动可以连接至前面讲到的音乐播放服务,并提供给用户一个可操作的(用 户界面)以对播放进行控制。这个活动可以调用 bindService()来建立连接,然后调用服务中定义的对 象来控制播放。 1.3、广播接收者(Broadcast receiver)组件的激活 应用程序可以通过将 Intent 对象传递给  Context.sendBroadcast()  Context.sendOrderedBroadcast()  Context.sendStickyBroadcast() 及其它类似方法来产生一个广播。Android 会通过 onReceive()方法将 intent 传递给所有对此广播有兴 趣的广播接收者。 2、关闭组件 内容提供者仅在响应 ContentResolver 提出请求的时候激活。而一个广播接收者仅在响应广播信息的时 候激活。所以,没有必要去显式的关闭这些组件。 而活动则不同,它提供了用户界面。与用户进行会话,所以只要会话依然持续,哪怕对话进程空闲,它 都会一直保持激活状态。与此相似,服务也会在很长一段时间内保持运行。所以 Android 提供方法有 序地关闭活动和服务。  可以通过调用它的 finish()方法来关闭一个活动。一个活动也可以通过调用 finishActivity()方法 来关闭另外一个活动(它用 startActivityForResult() 启动的)。  服务可以通过调用它的 stopSelf()方法来停止,或者调用 Context.stopService()。 当组件不再被使用的时候或者 Android 必须要为更多活跃的组件回收内存时,组件也可能会被系统关 闭。 3、清单(manifest)文件 当 Android 启动一个应用程序组件之前,它必须知道那个组件是存在的。所以,应用程序会在一个清 单(manifest)文件中声明它的组件,这个文件会被打包到 Android 包中。这个.apk 文件还将包括应 用程序的代码、文件以及其它资源。 这个清单文件是 XML 结构的文件,且所有的 Android 应用程序都把它叫做 AndroidManifest.xml。为 声明一个应用程序组件,它还会做很多额外工作,比如指明应用程序所需链接到的库的名称(除了默认 的 Android 库之外)以及声明应用程序期望获得的各种权限。 但清单文件的主要功能仍然是向 Android 声明应用程序的组件。举例说明,一个活动可以如下声明: AndroidManifest.xml 元素的 name 属性指定了实现了这个活动的 Activity 类的子类,icon 和 label 属性指向了包 含展示给用户的此活动的图标和标签的资源文件。 其它组件也以类似的方法声明—— 元素用于声明服务, 元素用于声明广播接收 者,而元素用于声明内容提供者。清单文件中未进行声明的活动、服务以及内容提供者将不 为系统所见,从而也就不会被运行。然而,广播接收者既可以在清单文件中声明,也可以在代码中动态 的创建(作为 BroadcastReceiver 对象)且调用 Context.registerReceiver()方式注册到系统。 4、Intent 过滤器 Intent 对象可以显式地指定目标组件。如果进行了这种指定,Android 会找到这个组件(依据清单文件 中的声明)并激活它。但如果 Intent 没有进行显式的指定,Android 就必须为它找到对于 intent 来说 最合适的组件。这个过程是通过比较 Intent 对象和所有可能对象的 intent 过滤器完成的。组件的 intent 过滤器会告知 Android 它所能处理的 intent 类型。如同其它关于组件的必要信息一样,它们在 清单文件中进行声明的。这里是上面示例的一个扩展,其中加入了针对活动的两个 intent 过滤器声明: AndroidManifest.xml 示例中的第一个过滤器——action:―android.intent.action.MAIN‖和 category: ―android.intent.category.LAUNCHER‖的组合,是常见的。它标记这个活动显示在应用程序启动器中, 用户在设备上看到的可启动的应用程序列表。换句话说,这个活动是应用程序的入口,是用户选择运行 这个应用程序后所见到的第一个活动。第二个过滤器声明了这个活动针对特定类型的数据。 一个组件可以拥有任意数量的 intent 过滤器,每个声明一系列不同的能力。如果它没有包含任何过滤 器,它将只能被显式声明了目标组件名称的意图激活。 对于广播接收者,它在代码中创建并注册 intent 过滤器,直接作为 IntentFilter 的对象实例化。其它过 滤器则在清单文件中设置。 如果您现在对这些概念还没有完全理解,没关系这里我仅是让大家有个印象,知道这些概念或术语的 存在,知道他们大概是做什么的。后面我还将陆续更详细地到这些东西并结合一些实例,到时候您就 会清楚地知道这些东西。 ——坚持就是胜利!关键是你能坚持吗?不能的话,你注定是个失败者。 引言 关于 Android 应用程序原理及术语,前面两篇:  Android 开发之旅:应用程序基础及组件  Android 开发之旅:应用程序基础及组件(续) 介绍了 Android 应用程序的进程运行方式:每一个应用程序运行在它自己的 Linux 进程中。当应用程 序中的任何代码需要执行时,Android 将启动进程;当它不在需要且系统资源被其他应用程序请求时, Android 将关闭进程。而且我们还知道了 Android 应用程序不像别的应用程序那样(有 Main 函数入口 点),它没有单一的程序入口点,但是它必须要有四个组件中的一个或几个:活动(Activities) 、服 务(Services) 、广播接收者(Broadcast receivers) 、内容提供者(Content providers)。且分别 介绍它们的作用,及如何激活和关闭它们、如何在清单文件(AndroidManifest.xml)中声明它们及 Intent 过滤器。 在简单回顾之后,本篇还是继续介绍 Android 应用程序原理及术语——活动与任务(Activities and Tasks)。  1、活动与任务概述  2、亲和度和新任务(Affinities and new tasks)  3、启动模式(Launch modes)  4、清除栈(Clearing the stack)  5、启动任务(Starting tasks) 1、活动与任务概述 如前所述,一个活动(activity)能启动另一个活动,包括定义在别的应用程序中的活动。再次举例说 明,假设你想让用户显示某地的街道地图。而且已经有了一个活动能做这个事情(假设这个活动叫做地 图查看器),因此你的活动要做的就是将请求信息放进一个 Intent 对象,然后将它传给 startActivity()。 地图查看器就启动并显示出地图。当用户点击返回按钮之后,你的活动就会重新出现在屏幕上。 对用户来说,这个地图查看器就好像是你的应用程序的活动一样,虽然它定义在其他的应用程序中且运 行在那个应用程序的进程中。Android 将这些活动保持在同一个任务(task)中以维持用户的体验。简 单地讲,任务是用户体验上的一个“应用程序”,是排成堆栈的一组相关活动。栈底的活动(根活动) 是起始活动——一般来讲,它是用户在应用程序启动器(也称应用程序列表,下同)中选择的一个活动。 栈顶的活动是正在运行的活动——它关注用户的行为(操作)。当一个活动启动另一个,新的活动被压 入栈顶,变为正在运行的活动。前面那个活动保存在栈中。当用户点击返回按钮时,当前活动从栈顶中 弹出,且前面那个活动恢复成为正在运行的活动。(关于栈的先进后出特性不要我在这里讲吧!) 栈中包含对象,因此如果一个活动(再次说明:活动是 Activity 的子类)启动了多个实例——例如多 个地图查看器,则栈对每个实例有一个独立的入口。(可以这样理解:假设有四个活动以这样的顺序排 在栈中——A-B-C-D,现在又有一个 C 的实例,则栈变成 A-B-C-D-C,这两个 C 的实例是独立的。)栈 中的活动从不会被重新排列,只会被压入、弹出。这点很好理解,因为活动的调用顺序是固定的。 任务是一栈的活动,而不是清单文件中声明的某个类或元素,因此无法独立于它的活动为任务赋值。整 个任务的值是在栈底活动(根活动)设置的。例如,下节将讨论的―任务亲和度‖,亲和度信息就是从任 务的根活动中获取的。 一个任务的所有活动作为一个整体运行。整个任务(整个活动栈)可置于前台或发送到后台。例如,假 设当前任务有四个活动在栈中——三个活动在当前活动下面。用户按下 HOME 键,切换到程序启动器, 并选择一个新的应用程序(实际上是一个新的任务)。当前任务进入后台,新任务的根活动将显示。接 着,过了一会,用户回到主屏幕并再次选择之前的应用程序(之前的任务)。那个任务栈中的所有四个 活动都变为前台运行。当用户按下返回键时,不是离开当前任务回到之前任务的根活动。相反,栈顶的 活动被移除且栈中的下一个活动将显示。 上面所描述的是活动和任务的默认行为,但是有方法来改变所有这些行为。活动与任务之间的联系及任 务中活动的行为,是由启动活动的 Intent 对象的标志(flags)和清单文件中活动元素的属性 共同决定的。 在这方面,主要的 Intent 标志有:  FLAG_ACTIVITY_NEW_TASK  FLAG_ACTIVITY_CLEAR_TOP  FLAG_ACTIVITY_RESET_TASK_IF_NEEDED  FLAG_ACTIVITY_SINGLE_TOP 主要的属性有:  taskAffinity  launchMode  allowTaskReparenting  clearTaskOnLaunch  alwaysRetainTaskState  finishOnTaskLaunch 接下来的小节将讨论这些标志和属性的作用,他们怎么交互,及使用的注意事项。 2、亲和度和新任务(Affinities and new tasks) 默认情况下,一个应用程序的所有活动互相之间都有一个亲和度(affinity)——也就是说,他们属于 同一个任务的偏好(preference)。然而,也可以通过元素的 taskAffinity 属性为每 个活动设置个体亲和度。定义在不同应用程序中的活动能够共享亲和度,同一个应用程序中的活动可以 分配不一样的亲和度。亲和度发挥作用的两种情况:1)启动活动的 Intent 对象包含 FLAG_ACTIVITY_NEW_TASK 标志时;2)一个活动的 allowTaskReparenting 属性为"true"时。  FLAG_ACTIVITY_NEW_TASK 标志 如前所述,默认情况下,一个新的活动被启动到调用 startActivity()方法的活动所在的任务。它被压入 调用它的活动的栈中。但是,如果传递给方法的 Intent 对象包含 FLAG_ACTIVITY_NEW_TASK 标志, 系统找一个不同的任务容纳活动。通常,顾名思义它表示一个新任务。但是,他并非一定如此。如果已 经存在一个任务与新活动亲和度一样,该活动将启动到该任务。如果不是,则启动一个新任务。  allowTaskReparenting 属性 如果一个活动的 allowTaskReparenting 属性为"true",它可以从启动它的任务转移到与它有亲和度 并转到前台运行的任务中。例如,假设一个天气预报的活动,但选择城市是一个旅游应用程序的一部分。 它与同一个应用程序中的其他活动具有相同的亲和度,且允许重新选择父活动(reparenting)。你的 一个活动启动天气预报活动,因此他初始是跟你的活动属于同一个任务。但是,当旅游应用程序切换到 前台运行时,天气预报活动将被重新分配和显示到该任务。 如果一个.apk 文件,从用户的角度看包含不止一个―应用程序‖,你可能要为与他们有关的些活动指定不 一样的亲和度。 3、启动模式(Launch modes) 有四种不同的启动模式可以分配到元素的 launchMody 属性:  "standard"(默认模式)  "singleTop "  "singleTask"  "singleInstance" 这些模式的在以下四方面不同:  哪个任务将持有响应意图(intent)的活动。对"standard"和"singleTop "模式,是产生意图的 任务(调用 startActivity()方法)——除非 Intent 对象包含 FLAG_ACTIVITY_NEW_TASK 标志。在那 种情况下,像上一节亲和度和新任务(Affinities and new tasks)所描述的那样选择一个不同的任务。 相反,"singleTask"和"singleInstance"模式,总是将活动标记为一个任务的根活动。他们定义一个任 务,而从不启动到其他任务。  活动是否可以实例化多次。"standard"或"singleTop "活动可以实例化多次。这些实例可以属于 多个任务,且一个给定任务可以包含同一个活动的多个实例。 相反,"singleTask"和"singleInstance"活动仅可以被实例化一次。因为这些活动是一个任务的根,这 个限制意味着设备上一个时间只有不多于一个任务的实例。  是否允许实例所在任务有其他活动。"singleInstance"活动所在任务只有它一个活动。如果他启 动别的活动,那些活动将启动到不同的任务中,无论它的模式如何——就好像 Intent 对象包含 FLAG_ACTIVITY_NEW_TASK 标志。在所有其他方面,"singleInstance"模式等同于"singleTask"模式。 其它三种模式允许多个活动属于一个任务。"singleTask"活动总是任务的根活动,但是它能启动其他 活动到它的任务。"standard"或"singleTop "活动的实例可以出现的栈中的任何位置。  响应一个意图时是否需要生成类的新实例。对于默认的"standard"模式,创建新的实例去响应 每一个新的意图。每个实例仅处理一个意图。对于"singleTop "模式,一个类已存在的实例可以重新 用了处理新的意图,如果它位于目标任务的活动栈的栈顶。如果不是在栈顶,就不可以重用。相反, 将创建一个新的实例并压入栈顶。 例如,一个任务的活动栈由根活动 A、B、C 和 D 组成,顺序为 A-B-C-D。当一个意图到达请求类型 D 时,如果 D 是默认的"standard"模式,将产生 D 类的新实例且栈变为 A-B-C-D-D。然而,如果 D 的启动模式是"singleTop ",已存在的 D 实例将去处理新的意图(因为它在栈顶)且栈仍然是 A-B-C-D。 如果,另一方面,到达的意图是请求类型 B 时,一个 B 的新实例将启动而不管 B 的模式是"standard" 还是"singleTop "(因为 B 不是在栈顶),因此栈的结构为 A-B-C-D-B。 如前所述,"singleTask"和"singleInstance"活动仅可以被实例化一次,因此他们的实例将处理所有的 新意图。一个"singleInstance"活动总是在栈顶(因为仅有一个活动在任务中),因此它总是在可以处 理意图的位置。然而,一个"singleTask"活动在栈中可能有或可能没有其他活动在它上面。如果有, 即它不在处理意图的位置,意图会被丢弃(即使意图被丢弃了,它的到来使任务转到并保持在前台运 行) 当一个已存在的活动被请求处理一个新的意图,Intent 对象将通过 onNewIntent()调用传到活动。(产 生启动活动的意图对象可以由 getIntent()获取。) 注意到当一个活动的新实例被创建去处理新意图时,用户总是可以按返回键返回到之前的状态(之前的 活动)。但是当一个已存在的活动实例去处理新意图是,用户不可以按返回键返回到意图到达之前的状 态。 4、清除栈(Clearing the stack) 如果用户离开一个任务很长时间,系统将会清除根活动之外的活动。当用户再次返回到这个任务时,像 用户离开时一样,仅显示初始的活动。这个想法是,一段时间后,用户可能已经放弃之前做的东西,及 返回任务做新的事情。这是默认情况,有些活动属性可以用来控制和改变这个行为。  alwaysRetainTaskState 属性 如果在任务的根活动中这个属性被设置为"true",刚才描述的默认行为将不会发生。任务将保留所有 的活动在它的栈中,甚至是离开很长一段时间。  clearTaskOnLaunch 属性 如果在任务的根活动中这个属性被设置为"true",只有用户离开就清除根活动之外的活动。换句话说, 它与 alwaysRetainTaskState 截然相反。用户总是返回到任务的初始状态,甚至是只离开一会。  finishOnTaskLaunch 属性 这个属性类似于 clearTaskOnLaunch,但是它作用于单个活动,而不是整个任务。而且它能移除任 何活动,包括根活动。当它被设置为"true",任务本次会话的活动的部分还存在,如果用户离开并返 回到任务时,它将不再存在。 有其他的方法强制从栈中移除活动。如果 Intent 对象包含 FLAG_ACTIVITY_CLEAR_TOP 标志,目标任 务已经有一个指定类型的活动实例,栈中该实例上面的其它活动将被移除而使它置于栈顶响应意图。如 果指定的活动的启动类型是"standard",它自己也将被移除出栈,且一个新的实例将被启动去处理到来 的意图。这是因为当模式是"standard"时,总是创建一个新的实例去处理新的意图。 FLAG_ACTIVITY_CLEAR_TOP 标志经常与 FLAG_ACTIVITY_NEW_TASK 一起使用。当一起使用时,这 些标志的方式是定位到另一个任务中的已存在的活动并把它放到可以处理意图的位置。 5、启动任务(Starting tasks) 通过给定活动一个意图过滤器"android.intent.action.MAIN"作为指定行为(action)和 "android.intent.category.LAUNCHER"指定种类(category),活动就被设置为任务的入口点了。上篇 Android 开发之旅:应用程序基础及组件(续)第四节 Intent 过滤器中我们举了这样一个例子,它将 导致该活动的图标(icon)和标签(label)显示在应用程序启动器,给用户启动它或启动之后任意时候 返回到它。 它的第二个功能非常重要:用户可以离开任务且之后可以返回到它。基于这个原因,两个启动模式 "singleTask"和"singleInstance"标记活动总是初始化一个任务来响应意图,仅可以使用在有 MAIN 和 LAUNCHER 过滤器的活动中。想象一下,如果没有这个过滤器将会发生什么:一个意图启动一个 "singleTask"活动,开始一个新任务,用户在任务中做一些操作。然后用户按下 HOME 键,任务现在 退到后台运行且被主屏幕遮蔽住。而且,由于活动不在应用程序启动器中显示,用户无法再返回。 类似的困难也出现在 FLAG_ACTIVITY_NEW_TASK 标志。如果这个标志导致一个活动开始一个新的任 务且用户按 HOME 键离开它,就必须要有某种方法是用户能够导航回来。一些实体(如通知管理器) 总是在外部任务启动活动,从不作为他们自己的一部分,因此他们总是将带 FLAG_ACTIVITY_NEW_TASK 标志的意图传到 startActivity()方法启动活动。如果你有活动能调用外部 实体,可以使用此标志,注意用户有一个独立的方式返回到开始的任务。 如果您希望用户离开活动后就不能再回到这个活动,可以将元素的 finishOnTaskLaunch 属性设置为"true"。可以参见清除栈那节。 引言 当应用程序的组件第一次运行时,Android 将启动一个只有一个执行线程的 Linux 进程。默认,应用程 序所有的组件运行在这个进程和线程中。然而,你可以安排组件运行在其他进程中,且你可以为进程衍 生出其它线程。本文从下面几点来介绍 Android 的进程与线程:  1、进程  2、线程 o 2.1、远程过程调用(Remote procedure calls,RPCs) o 1、进程 2.2、线程安全方法 组件运行于哪个进程中由清单文件控制。组件元素——, 都有一个 process 属性可以指定组件运行在哪个进程中。这个属性可以设置为每个组件运行在自己的进 程中,或者某些组件共享一个进程而其他的不共享。他们还可以设置为不同应用程序的组件运行在同一 个进程中——假设这些应用程序共享同一个 Linux 用户 ID 且被分配了同样的权限。元素 也有 process 属性,为所有的组件设置一个默认值。 所有的组件都在特定进程的主线程中实例化,且系统调用组件是由主线程派遣。不会为每个实例创建单 独的线程,因此,对应这些调用的方法——诸如 View.onKeyDown()报告用用户的行为和生命周期通知, 总是运行在进程的主线程中。这意味着,没有组件当被系统调用时应该执行很长时间或阻塞操作(如网 络操作或循环计算),因为这将阻塞进程中的其它组件。你可以为长操作衍生独立的线程。 public boolean onKeyDown(int keyCode,KeyEvent event):默认实现 KeyEvent.Callback.onKeyMultiple(),当按下视图的 KEYCODE_DPAD_CENTER 或 KEYCODE_ENTER 然后释放时执行,如果视图可用且可点击。 参数 keyCode-表示按钮被按下的键码,来自 KeyEvent event-定义了按钮动作的 KeyEvent 对象 返回值 如果你处理事件,返回 true;如果你想下一个接收者处理事件,返回 false。 当内存剩余较小且其它进程请求较大内存并需要立即分配,Android 要回收某些进程,进程中的应用程 序组件会被销毁。当他们再次运行时,会重新开始一个进程。 当决定终结哪个进程时,Android 会权衡他们对用户重要性的相对权值。例如,与运行在屏幕可见的活 动进程相比(前台进程),它更容易关闭一个进程,它的活动在屏幕是不可见(后台进程)。决定是否 终结进程,取决于运行在进程中的组件状态。关于组件的状态,将在后面一篇——组件生命周期中介绍。 2、线程 虽然你可能会将你的应用程序限制在一个进程中,但有时候你会需要衍生一个线程做一些后台工作。因 为用户界面必须很快地响应用户的操作,所以活动寄宿的线程不应该做一些耗时的操作如网络下载。任 何不可能在短时间完成的操作应该分配到别的线程。 线程在代码中是用标准的 Java 线程对象创建的,Android 提供了一些方便的类来管理线程——Looper 用于在线程中运行消息循环、Handler 用户处理消息、HandlerThread 用户设置一个消息循环的线程。 Looper 类 该类用户在线程中运行消息循环。线程默认没有消息循环,可以在线程中调用 prepare()创建一个运行循环; 然后调用 loop()处理消息直到循环结束。大部分消息循环交互是通过 Handler 类。下面是一个典型的执行一 个 Looper 线程的例子,分别使用 prepare()和 loop()创建一个初始的 Handler 与 Looper 交互: class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here } }; Looper.loop(); } } 更多的关于 Looper 的信息及 Handler、HandlerThread 请参阅相关资料。 2.1、远程过程调用(Remote procedure calls,RPCs) Android 有一个轻量级的远程过程调用机制——方法在本地调用却在远程(另外一个进程中)执行,结 果返回给调用者。这需要将方法调用和它伴随的数据分解为操作系统能够理解的层次,从本地进程和地 址空间传输到远程进程和地址空间,并重新组装调用。返回值以相反方向传输。Android 提供了做这些 工作的所有代码,这样我们可以专注于定义和执行 RPC 接口本身。 一个 RPC 接口仅包含方法。所有的方法同步地执行(本地方法阻塞直到远程方法执行完成),即使是 没有返回值。简言之,该机制工作原理如下:首先,你用简单的 IDL(interface definition language, 接口定义语言)声明一个你想实现的 RPC 接口。从这个声明中,aidl 工具生成一个 Java 接口定义,提 供给本地和远程进程。它包含两个内部类,如下图所示: 内部类有管理你用 IDL 定义的接口的远程过程调用所需要的所有代码。这两个内部类都实现了 IBinder 接口。其中之一就是在本地由系统内部使用,你写代码可以忽略它。另外一个是 Stub,扩展自 Binder 类。除了用于有效地 IPC(interprocess communication)调用的内部代码,内部类在 RPC 接口声明中 还包含方法声明。你可以定义 Stub 的子类实现这些方法,如图中所示。 通常情况下,远程过程有一个服务管理(因为服务能通知系统关于进程和它连接的其它进程的信息)。 它有由 aidl 工具生成的接口文件和 Stub 子类实现的 RPC 方法。服务的客户端仅有由 aidl 工具生成的 接口文件。 下面介绍服务如何与它的客户端建立连接:  服务的客户端(在本地端的)应该实现 onServiceConnected() 和 onServiceDisconnected() 方 法,因此当与远程服务建立连接成功和断开连接是会通知它。然后调用 bindService() 建立连接。  服务的 onBind()方法将实现为接受或拒绝连接,者取决于它接受到的意图(该意图传送到 binServive())。如果连接被接受,它返回一个 Stub 子类的实例。  如果服务接受连接,Android 调用客户端的 onServiceConnected()方法且传递给它一个 IBinder 对象,返回由服务管理的 Stub 子类的一个代理。通过代理,客户端可以调用远程服务。 这里只是简单地描述,省略了一些 RPC 机制的细节。你可以查阅相关资料或继续关注 Android 开发之 旅,后面将为你奉上。 2.2、线程安全方法 在一些情况下,你实现的方法可能会被不止一个线程调用,因此必须写成线程安全的。这对远程调用方 法是正确的——如上一节讨论的 RPC 机制。当从 IBinder 进程中调用一个 IBinder 对象中实现的一个方 法,这个方法在调用者的线程中执行。然而,当从别的进程中调用,方法将在 Android 维护的 IBinder 进程中的线程池中选择一个执行,它不在进程的主线程中执行。例如,一个服务的 onBind()方法在服 务进程的主线程中被调用,在 onBind()返回的对象中执行的方法(例如,实现 RPC 方法的 Stub 子类) 将在线程池中被调用。由于服务可以有一个以上的客户端,所以同时可以有一个以上的线程在执行同一 个 IBinder 方法。因此,IBinder 的方法必须是线程安全的。 同样,一个内容提供者可以接受其它进程产生的数据请求。虽然 ContentResolver 和 ContentProvider 类隐藏进程通信如何管理的,对应哪些请求的 ContentResolver 方法——query()、insert()、delete()、 update()、getType(),在内容提供者的进程的线程池中被调用,而不是在这一进程的主线程中。因为这 些方法可以同时从任意数量的线程中调用,他们也必须实现为线程安全的。 Android 开发之旅:组件生命周期(二) 2010-05-06 23:59 by 吴秦, 1360 visits, 网摘, 收藏, 编辑 引言 应用程序组件有一个生命周期——一开始 Android 实例化他们响应意图,直到结束实例被销毁。在这期 间,他们有时候处于激活状态,有时候处于非激活状态;对于活动,对用户有时候可见,有时候不可见。 组件生命周期将讨论活动、服务、广播接收者的生命周期——包括在生命周期中他们可能的状态、通知 状态改变的方法、及这些状态的组件寄宿的进程被终结和实例被销毁的可能性。 上篇 Android 开发之旅:组件生命周期(一)讲解了论活动的生命周期及他们可能的状态、通知状态 改变的方法。本篇将介绍服务和广播接收者的生命周期:  服务生命周期  广播接收者生命周期 1、服务生命周期 一个服务可以用在两个方面:  它可以启动且允许一直运行直到有人停止它,或者它自己停止。在这种模式,通过调用 Context.startService()启动服务及通过调用 Context.stopService()停止服务。服务也可以通过调用 Service.stopSelf()或 Service.stopSelfResult()停止自己。仅需要调用一次 stopService()停止服务,而 不管调用 startService()了多少次。  通过使用相关接口可以编程地操作服务。客户端建立与 Service 对象的一个连接及使用该连接 调入服务。连接通过调用 Context.bindService()建立,通过调用 Context.unbindService()关闭。多个 客户端可以绑定到同一个服务。如果服务尚未启动,bindService()可以选择启动它。 这两种模式并不是完全分离的。你可以绑定到一个用 startService()启动的服务。例如,一个后台音乐 服务可以通过使用定义了音乐播放的 Intent 对象调用 startService()启动。直到后来,用户可能想对播 放器做一些控制或者获取当前歌曲的一些信息,一个活动将调用 bindService()与服务建立连接。在这 种情况下,实际上直到最后一个绑定关闭 stopService()并不会停止。 像活动一样,一个服务也有生命周期方法,你可以执行监视它的状态改变。但是比活动的生命周期方法 更少,只有三个且它们是公有的(public)而不是受保护的(protected)(说明:活动的生命周期方法 是 protected 的):  void onCreate()  void onStart(Intent intent)  void onDestory() 通过这三个方法,你可以监视服务生命周期的两个嵌套循环:  服务的整个生命时间(entire lifetime),从调用 onCreate()到相应地调用 onDestory()。像 一个活动一样,服务在 onCreate()中做一些初始设置,且在中释放所有的资源。例如,一个音乐播放 服务可以在 onCreate()中创建线程,然后在 onDestory()中停止线程。  服务的活跃生命时间(active lifetime),从调用 onStart()开始。这个方法传递参数是传送给 startService()的 Intent 对象。音乐服务将打开 Intent,了解播放哪个音乐并且开始播放。 没有相应的回调方法,因为服务停止没有 onStop()方法。 startService()和 onDestory()被所有服务调用,不管是通过 Context.startService()启动还是通过 Context.bindService()启动的。然而,onStart()仅被通过 startService()启动的服务调用。 如果一个服务允许别的绑定到它,有一些额外的回调方法来实现它:  IBinder onBind(Intent intent)  boolean onUnbind(Intent intent)  void onRebind(Intent intent) onBind()回调传递的参数是传给 bindService()的 Intent 对象,onUnbind()回调传递的参数是传给 unbindService()的 Intent 对象。如果服务允许绑定,onBind()返回客户端与服务交互的通信通道。 onUnbind()方法可以要求调用 onRebind(),如果一个新的客户端连接到服务。 下图解释了服务的回调方法。虽然,它分离了由 startService()启动的服务和由 bindService()启动的服 务,记住任何服务,无论它怎么启动的,都可能允许客户端绑定到它,因此任何服务可能接收 onBind() 和 onUnbind()调用。 2、广播接收者生命周期 一个广播接收者有一个回调方法:void onReceive(Context curContext, Intent broadcastMsg)。当一个 广播消息到达接收者是,Android 调用它的 onReceive()方法并传递给它包含消息的 Intent 对象。广播 接收者被认为仅当它执行这个方法时是活跃的。当 onReceive()返回后,它是不活跃的。 有一个活跃的广播接收者的进程是受保护的,不会被杀死。但是系统可以在任何时候杀死仅有不活跃组 件的进程,当占用的内存别的进程需要时。 这带来一个问题,当一个广播消息的响应时费时的,因此应该在独立的线程中做这些事,远离用户界面 其它组件运行的主线程。如果 onReceive()衍生线程然后返回,整个进程,包括新的线程,被判定为不 活跃的(除非进程中的其它应用程序组件是活跃的),将使它处于被杀的危机。解决这个问题的方法是 onReceive()启动一个服务,及时服务做这个工作,因此系统知道进程中有活跃的工作在做。 Android 开发之旅:组件生命周期(三) 2010-05-07 19:39 by 吴秦, 1456 visits, 网摘, 收藏, 编辑 Android 系统试图尽可能长地保持一个应用程序进程,但是当内存低时它最终还是需要移除旧的进程。 为了决定保持哪个进程及杀死哪个进程,Android 将每个进程放入一个基于运行于其中的组件的重要性 等级和这些组件的状态。重要性最低的进程首先被杀死,然后是次低,以此类推。总共有 5 个层次等级。 下列清单按重要性顺序列出: 1. 前台进程,用户当前工作所需要的。一个进程如果满足下列任何条件被认为是前台进程: 1. 它正运行着一个正在与用户交互的活动(Activity 对象的 onResume()方法已经被调用)。 2. 它寄宿了一个服务,该服务与一个与用户交互的活动绑定。 3. 它有一个 Service 对象执行它的生命周期回调(onCreate()、onStart()、onDestroy())。 4. 它有一个 BroadcastReceiver 对象执行他的 onReceive()方法。 在给定时间内仅有少数的前台进程存在。仅作为最后采取的措施他们才会被杀掉——如果内 存太低以至于他们不能继续运行。一般来说,就在那时,设备达到一个内存???状态,因 此杀掉某些前台进程以保持用户界面响应。 2. 可视进程,他没有任何前台组件,但是仍然能影响用户在屏幕上看到东西。一个进程满足下面 任何一个条件都被认为是可视的: 1. 它寄宿着一个不是前台的活动,但是它对用户仍可见(它的 onPause()方法已经被调用)。 举例来说,这可能发送在,如果一个前台活动是一个对话框且运行之前的活动在其后面仍可 视。 2. 它寄宿着一个服务,该服务绑定到一个可视的活动。 一个可视进程被认为是及其重要的且不会被杀死,除非为了保持前台进程运行。 3. 服务进程,是一个运行着一个用 startService()方法启动的服务,并且该服务并没有落入上面 2 种分类。虽然服务进程没有直接关系到任何用户可见的,它们通常做用户关心的事(诸如在后台 播放 mp3 或者从网络上下载数据),因此系统保持它们运行,除非没有足够内存随着所有的前台 进程和可视进程保持它们。 4. 后台进程,是一个保持着一个当前对用户不可视的活动(已经调用 Activity 对象的 onStop()方 法)。这些进程没有直接影响用户体验,并且可以在任何时候被杀以收回内存用于一个前台、可 视、服务进程。一般地有很多后台进程运行着,因此它们保持在一个 LRU(least recently used, 即最近最少使用,如果您学过操作系统的话会觉得它很熟悉,跟内存的页面置换算法 LRU 一样。) 列表以确保最近使用最多的活动的进程最后被杀。如果一个活动执行正确地执行它的生命周期方 法,且捕获它当前的状态,杀掉它对用户的体验没有有害的影响。 5. 空进程,是一个没有保持活跃的应用程序组件的进程。保持这个进程可用的唯一原因是作为一 个 cache 以提高下次启动组件的速度。系统进程杀死这些进程,以在进程 cache 和潜在的内核 cache 之间平衡整个系统资源。 Android 把进程标记为它可以的最高级,即进程中活跃的组件中重要性最高的那个(选取重要性最高的 那个作为进程的重要性级别)。例如,有一个进程寄宿着一个服务和一个可视活动,进程的级别被设置 为可视进程级别,而不是服务进程级别(因为可视进程级别比服务进程级别高)。 此外,一个进程的排名因为其他进程依赖它而上升。一个进程服务其它进程,它的排名从不会比它服务 的进程低。例如,进程 A 中的一个内容提供者服务进程 B 中的一个客户,或者进程 A 中的一个服务绑 定到进程 B 中的一个组件,进程 A 总是被认为比进程 B 重要。 因为一个运行一个服务进程排名比一个运行后台活动的进程排名高,一个活动启动一个服务来初始化一 个长时间运行操作,而不是简单地衍生一个线程——特别是如果操作很可能会拖垮活动。这方面的例子 是在后台播放音乐和上传相机拍摄的图片到一个网站。使用服务保证操作至少有―服务进程‖的优先级, 无论活动发生什么情况。 ——量变产生质变,如果你从第一篇一直看到了这篇,可以说这就是你的质变点之一。 回顾及展望 经过数篇对 Android 应用程序的原理的讲述,现在我们大概回顾一下。  首先我们利用 Hello World 程序介绍了一个 Android 应用程序的目录结构,包括 src 文件夹、 gen 文件夹、Android x 文件夹、assets 文件夹、AndroidMainifest.xml、default.properties;  接下来我们又站在架构的高度分析了一下 Android 系统的主要组成部分,包括 Linux Kernel、 Android Runtime、Libraries、Application Framework、Application;  接下来我们又介绍了 Android 应用程序的运行及应用程序组件,包括活动(Activities)、服务 (Services)、广播接收者(Broadcast receivers)、内容提供者(Content providers)等内容;  接着我们又介绍了如何激活及关闭组件,还有简单的介绍了 AndroidMainifest.xml、Intent 及 其过滤器(这两者我们以后还要通过例子或者单独开篇深入分析);  接着我们站在 Android 应用程序的角度分析 Android 中活动与任务,包括活动与任务概述、亲 和度和新任务(Affinities and new tasks)、启动模式(Launch modes)、清除栈(Clearing the stack)、 启动任务(Starting tasks);  接着我们在 Android 应用程序运行的角度,简单分析了 Android 应用程序的进程与线程;  最后我们用分析了 Android 应用程序组件的生命周期,包括活动的生命周期及他们可能的状态、 服务生命周期、广播接收者生命周期、Android 应用程序进程的分类及重要性等级。 至此,我们终于算是完全算是双脚步入 Android 开发的大门了,但我们现在还只能算是金字塔底端的 那群人,还需要不断地实践、实践、再实践。而且上面所讲的是作为一个真正 Android 开发人员必须 要深刻理解的东西,如果您还没有达到深刻的程度那请你回去再浏览一遍,然后跟着我的这个系列继续 深入学习,在接下来的文章我将更多的是利用实例来解析这些东西。下面我再次用 Hello World 程序来 分析一下 Android 应用程序,主要内容如下:  ―Hello World!‖显示浅析  ―Hello World!‖的手术(一)  ―Hello World!‖的手术(二)  ―Hello World!‖的手术(三) 1、“Hello World!”浅析 首先我们再次简单地新建一个 Hello World 项目,它的布局文件 res\layout\main.xml 的代码如下: 元素的 android:text 就是我们在屏幕上显示的―Hello World, HelloWorld!‖,android:text 的值是―@string/hello‖,它是如何在屏幕上显示―Hello World, HelloWorld!‖ 的呢?。 在 main.xml 文件中以这种格式: @[package:]string/some_name (where some_name is the name of a specific string) 引用 res/values/strings.xml 文件中的字符串,其中 some_name 是要引用的字符串的名字。strings.xml 文件代码如下: Hello World, HelloWorld! HelloWorld 由此可见,上面那个的 android:text 引用的字符串是―Hello World, HelloWorld!‖。接着想 象一下,―Hello World, HelloWorld!‖何时加载显示的呢? Note:这种的 text 的值是存储在 strings.xml 中的,而不是硬编码的。这样的好处是,当我们在 strings.xml 中修改 hello 的具体值时,不需要在 main.xml 中修改。 我们来看下 src 目录下 skynet.com.cnblogs.www 包(就是新建 Hello World 项目时定义的包名)中的 HelloWorld.java 文件,代码如下: package skynet.com.cnblogs.www; import android.app.Activity; import android.os.Bundle; public class HelloWorld extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } } 可以看出在创建活动时,即 void onCreate(Bundle saveInstanceState)中,在 HelloWorld 中重写了它, 在该方法中首先调用了父类的 onCreate 方法且接着调用了 setContentView(R.layout.main)方法。是的, 就是在这个方法中,根据 main.xml 文件将其显示出来,因为 R.layout.main 是表示布局资源文件 main.xml 编译后的对象,Eclipse 插件会自动在 R.java 文件中创建这个引用。main.xml 中定义了 ,然后根据它的 android:text 属性引用到 strings.xml 文件中的Hello World, HelloWorld!元素,然后将它显示到屏幕上。 从活动的生命周期可以知道,任何一个活动启动的一个方法是 onCreate()方法,在这里做一些初始化的 工作,诸如创建视图、绑定数据列表等。在 HelloWorld 项目中,就是调用 setContentView 进行初始 化工作,将 Hello World, HelloWorld!显示到屏幕上。 至此,我们对 Hello World 的认识更加深入了一点!下面我们让拿起手术刀对它进行一个手术。 2、Hello World 的手术(一) 我们将 main.xml 文件中的元素删掉,取而代之用一个 Button 来显示―Hello World!‖。代 码如下:

Top_arrow
回到顶部
EEWORLD下载中心所有资源均来自网友分享,如有侵权,请发送举报邮件到客服邮箱bbs_service@eeworld.com.cn 或通过站内短信息或QQ:273568022联系管理员 高进,我们会尽快处理。