安卓设计模式最佳实践-全-
安卓设计模式最佳实践(全)
原文:
zh.annas-archive.org/md5/CCA23E4331AE2938F4F732DE02106746
译者:飞龙
前言
《Eclipse 下的 Android 开发工具》将向你展示如何使用 Eclipse 的 ADT(Android 开发工具)快速建立 Android 项目,创建应用程序 UI,调试以及导出签名(或未签名)的.apk 发布包。本书从 ADT 的安装开始,讨论重要的工具,并从零开始指导你进行 Android 应用开发,演示不同的概念和实现方法,最终帮助你进行分发。
本书涵盖的内容
第一章,《安装 Eclipse、ADT 和 SDK》,指导你安装进行 Android 应用开发所需的 Eclipse 和 ADT(Android 开发工具)。
第二章,《IDE 的重要特性》,描述了 Eclipse 和 ADT 环境中几个对开发原生 Android 应用有用的特性。
第三章,《创建一个新的 Android 项目》,指导你创建一个新项目并演示简单部件的使用。它还指导编译、调试和运行应用程序。
第四章,《合并多媒体元素》,将教你如何包含多媒体元素并在应用中处理多个屏幕。
第五章,《添加 RadioButton、CheckBox、Menu 和 Preferences》,涉及添加菜单和偏好设置屏幕以及单选按钮和复选框的使用。
第六章,《处理多种屏幕类型》,教你如何应对不同的屏幕类型和方向。
第七章,《添加外部库》,指导你添加外部库,即 AdMob 库并在应用中添加广告。
第八章,《签名和分发 APK》,展示了签名和分发 Android 应用的步骤。
你需要为这本书准备的东西
建议使用以下规格的笔记本电脑或 PC 以获得更好的开发性能:
-
4 GB 内存
-
Windows 7 操作系统
-
双核/i 系列处理器
本书适合的读者
《Eclipse 下的 Android 开发工具》面向初学者和希望了解更多关于 Android 开发的现有开发者。假设你有 Java 编程经验并且使用过 IDE 进行开发。
约定
在这本书中,你将发现多种文本样式,用于区分不同类型的信息。以下是一些样式的例子及其含义的解释。
文本中的代码字、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 处理都如下所示:"我们可以通过使用include
指令包含其他上下文。"
代码块设置如下:
[default]
exten => s,1,Dial(Zap/1|30)
exten => s,2,Voicemail(u100)
exten => s,102,Voicemail(b100)
exten => i,1,Voicemail(s0)
当我们希望引起你对代码块中某个特定部分的注意时,相关的行或项目会以粗体显示:
[default]
exten => s,1,Dial(Zap/1|30)
exten => s,2,Voicemail(u100)
exten => s,102,Voicemail(b100)
exten => i,1,Voicemail(s0)
任何命令行输入或输出都如下所示:
# cp /usr/src/asterisk-addons/configs/cdr_mysql.conf.sample
/etc/asterisk/cdr_mysql.conf
新术语和重要词汇会以粗体显示。你在屏幕上看到的内容,例如菜单或对话框中的单词,会在文本中以这样的形式出现:"点击下一步按钮,你会进入下一个屏幕"。
注意
警告或重要提示会以这样的方框显示。
小贴士
小技巧会以这样的形式出现。
读者反馈
我们始终欢迎读者的反馈。让我们知道你对这本书的看法——你喜欢或可能不喜欢的内容。读者的反馈对我们开发能让你们充分利用的标题非常重要。
要向我们发送一般反馈,只需发送电子邮件至<feedback@packtpub.com>
,并在邮件的主题中提及书名。如果你有专业知识的话题,并且有兴趣撰写或为书籍做出贡献,请查看我们在www.packtpub.com/authors上的作者指南。
客户支持
既然你现在拥有了 Packt 的一本书,我们有一些事情可以帮助你最大限度地利用你的购买。
下载示例代码
你可以从你在www.packtpub.com
的账户下载你购买的所有 Packt 书籍的示例代码文件。如果你在其他地方购买了这本书,可以访问www.packtpub.com/support
注册,我们会直接将文件通过电子邮件发送给你。
勘误
尽管我们已经竭尽所能确保内容的准确性,但错误仍然在所难免。如果你在我们的书中发现了一个错误——可能是文本或代码中的错误——如果你能向我们报告,我们将不胜感激。这样做,你可以避免其他读者的困扰,并帮助我们改进本书后续版本。如果你发现任何勘误信息,请通过访问www.packtpub.com/submit-errata
,选择你的书籍,点击勘误提交表单链接,并输入你的勘误详情。一旦你的勘误信息被核实,你的提交将被接受,并且勘误信息将被上传到我们的网站,或添加到该标题下的现有勘误列表中。任何现有的勘误信息可以通过访问www.packtpub.com/support
并选择你的标题来查看。
盗版
互联网上版权资料的盗版问题在所有媒体中持续存在。在 Packt,我们非常重视对我们版权和许可的保护。如果您在网上以任何形式遇到我们作品的非法副本,请立即向我们提供位置地址或网站名称,以便我们可以寻求补救措施。
如果您有疑似盗版资料的链接,请联系<copyright@packtpub.com>
。
我们感谢您在保护我们作者权益方面所提供的帮助,以及我们向您提供有价值内容的能力。
咨询问题
如果您在书的任何方面遇到问题,可以联系<questions@packtpub.com>
,我们将尽力解决。
第一章:安装 Eclipse、ADT 和 SDK
本章节作为在 Windows 环境下开发 Android 所需的所有开发工具包的安装说明。它分为以下子主题:
-
Android 平台简介
-
安装 Java 开发工具包(JDK)
-
安装 Android SDK
-
安装 Eclipse(Juno)
-
在 Eclipse(Juno)中安装 Android 开发工具包(ADT)
-
将 Android SDK 链接到 Eclipse
在我们开始安装指南之前,Android 开发者必须了解一些基本知识。
介绍 Android 平台
简而言之,Android 是一个基于 Linux 的触摸屏设备操作系统,由 Android Inc.开发,由 Google 资助,并于 2005 年后期收购。Android 的测试版在 2007 年 11 月回归,商业版本 1.0 在 2008 年 9 月发布。截至 2013 年,全球有超过 5 亿活跃设备使用 Android 操作系统。
什么是 Android?
Android 是移动设备的软件堆栈,包括操作系统、中间件和关键应用(平台)。Android 的软件开发工具包(SDK)提供了使用 Java 编程语言在 Android 平台上开始开发应用程序所需的工具和应用程序编程接口(API)。Android 的内核是 Linux。
介绍 Android 应用
在 Android 上运行的移动软件应用程序称为 Android 应用。这些应用使用.apk
作为安装文件扩展名。有一些流行的移动应用示例,如 Foursquare、愤怒的小鸟、水果忍者等。
主要在 Eclipse 环境中,我们使用 Java,然后编译成 Dalvik 字节码(不是普通的 Java 字节码)。Android 在内部提供Dalvik 虚拟机(DVM)(不是 Java 虚拟机 JVM)。Dalvik VM 不与 Java SE 和 Java ME 库联盟,并建立在 Apache Harmony java 实现上。
什么是 Dalvik 虚拟机?
Dalvik VM 是一种基于寄存器的架构,由丹·伯恩斯坦创作。它针对低内存需求进行了优化,虚拟机被简化以占用更少的空间和更低的功耗。
了解 API 级别
API 级别是一个整数值,唯一标识由 Android 平台版本提供框架 API 修订。
Android 平台提供了一个框架 API,应用程序可以使用它来与底层的 Android 系统交互。框架 API 包括:
-
一组核心的包和类
-
一组用于声明清单文件的 XML 元素和属性
-
一组用于声明和访问资源的 XML 元素和属性
-
一组意图(Intents)
-
一组应用程序可以请求的权限,以及系统中包含的权限强制执行
Android 有多少个版本(发行版)?
截至 2013 年 5 月 1 日的最新分布统计如图所示。它表明 Android 2.3.3 拥有最大的市场份额;然而,Android 4.1.x 正在获得动力并将占据主导地位。需要知道的是,如果应用主要针对的是某个 Android 版本,它将无法在之前的 Android 版本上运行。
例如,如果你正在为 Android 2.2(API 级别 8)开发应用,那么该应用将无法在 Android 2.1(API 级别 7)及以下版本上运行。然而,该应用与 Android 2.2 及更高版本兼容。
安卓 API 级别分布的饼图(来源:developer.android.com/about/dashboards/index.html
)
安卓 API 级别分布(来源:developer.android.com/about/dashboards/index.html
)
准备 Android 开发
在本章的这一部分,我们将了解如何在 Eclipse Juno(4.2)上为 Android 安装开发环境。Eclipse 是 Android 开发的主要 IDE(见以下截图)。我们需要安装 Eclipse 扩展 ADT(Android 开发工具包)以开发 Android 应用:
Eclipse 中的 ADT 操作
在下载 Android 包之前,必须确保有 Google API 的网络连接,这一点在继续操作前需要特别注意。以下是使用 Windows 和 Eclipse Juno 的步骤:
需要的软件:
-
来自 Oracle 的最新 JDK1.6.x
-
最新 Android SDK
-
Eclipse 4.2(Juno)
安装 JDK
要检查你的电脑是否已安装 JDK 并且安装正确,请打开命令提示符,并输入javac –version
(如下截图所示)。建议为 Android 应用开发安装 JDK 1.6.x,因为它可能会抱怨编译器合规级别大于 6,可能会遇到问题:
检查 JDK 版本
你可以从下载站点下载 JDK 1.6(Java 开发工具包)并安装它。确保安装后设置了 JAVA_HOME,并通过执行前面的命令来检查版本。www.oracle.com/technetwork/java/javase/downloads/index.html
(见以下截图)。
如果我们已安装 java 1.6.x,则可以跳过此步骤:
Java PATH 设置
安装 Android SDK
创建一个名为 android-dev
的文件夹(android-dev 只是一个建议,你也可以选择另一个名称)。本章将一直使用 android-dev
文件夹。此文件夹用于存放进行 Android 开发所需的所有软件。在另一个流程中还需要此文件夹。
从 developer.android.com/sdk/index.html
下载,并将此软件安装到 android-dev
文件夹中。请记住,此下载仅提供 Android SDK 的基本工具,而非完整安装。稍后,我们需要下载 Android 系统映像、API、示例、文档和其他库:
Android SDK 下载页面
下载完成后,将 SDK 安装在之前提到的文件夹中;在 C:\android-dev\android-sdk
,如下截图所示。
在安装过程中,Android SDK 将检测到机器中的 Java 开发工具包。如果我们安装了最新的 JDK,应该不会有问题:
Android SDK 安装路径
安装 Eclipse (Juno)
Eclipse Juno (4.2) 可在 www.eclipse.org/downloads/
下载:
Eclipse Classic 下载页面
Eclipse 以 ZIP 文件形式提供,因此只需解压它并找到 eclipse.exe
文件来运行。
立即在之前创建的文件夹中解压 Eclipse(在 C:\android-dev
中)。解压后,创建一个桌面快捷方式以便使用,如下截图所示:
创建 Eclipse 快捷方式
在 Eclipse Juno 中安装 ADT
通过识别 Eclipse 安装文件夹并双击 eclipse.exe
(或在桌面双击快捷方式)来运行 Eclipse。提供一个用于存储所有项目源代码的文件夹。再次强调,要在 android-dev
文件夹下创建此文件夹,如下截图所示:
选择 Eclipse 工作空间
这个新的 Eclipse 安装不提供 Android 开发工具包(ADT)插件。要安装此插件,请导航到 窗口 | 首选项 打开首选项面板。点击 安装/更新 | 可用软件站点(在左侧面板上)。在右侧面板上点击 添加 按钮以添加软件下载站点(同样需要互联网连接)。
将会弹出另一个窗口。在名称中提供 ADT
(例如),在位置中提供 https://dl-ssl.google.com/android/eclipse/
(如 developer.android.com/sdk/eclipse-adt.html
所示):
在可用软件对话框中,选中开发者工具旁边的复选框,然后点击下一步。在下一个窗口中,您将看到要下载的工具列表。除了NDK 插件外,选择所有工具并点击下一步。我们将在下一章讨论这些工具:
选择 ADT 和 SDK 工具
阅读并接受许可协议,然后点击完成。如果出现安全警告,提示无法验证软件的真实性或有效性,请点击确定。安装完成后,重启Eclipse。
将 Android SDK 链接到 Eclipse
运行 Eclipse。在窗口 | 首选项中,点击Android。找到您安装android-sdk
的文件夹位置,如下截图所示:
Eclipse 中的 Android 首选项
点击应用并按下确定。
接下来要做的就是下载 Android APIs 和操作系统映像。安装 Android SDK 是耗时的。它需要一条流畅的宽带线路,因为安装完成后,您需要下载 Android 和 Google API 的 API 包。
要开始这个操作,请点击如下截图所示的Android SDK 管理器图标:
Android SDK 管理器图标
您将获得所有 Android 版本的所有 SDK 平台的列表。我建议您有选择性地先下载您的目标平台。如果您要为Froyo(Android 2.2)开发应用,则需要下载 API 版本 8。稍后,当您有更多时间时,可以回来下载其他版本。如果没有时间和互联网数据限制,那么您可以下载所有内容。这将获取 API 包,Android 操作系统映像,调试工具以及与 Android 开发相关的其他软件。
本次我们将下载带有Jellybean系统映像和API 级别16 的最新 SDK,如下截图所示:
安装带有 API 级别 16 的 SDK
在点击安装按钮之前,我想分享一个重要提示。在进行此操作时,我们可能会遇到无特定原因的连接重置问题。为了解决这个问题,在Android SDK 管理器窗口中,导航到工具 | 选项。取消勾选强制https://...源使用 https://...获取的选项,然后点击关闭(如下截图所示)。现在您可以开始安装 SDK 和 API 了:
下载完 SDK、API 和系统镜像后,重启 Eclipse。等待是值得的!在安装和下载软件包近两小时后,我得到了这个用于屏幕布局安排的精美图形界面,如下面的截图所示。检查Android 首选项窗口,你可能会在 API 列表中看到Android 4.1。要添加另一个 API,你还需要通过 Android SDK 管理器下载:
Android API 列表
为了避免在 Eclipse 上设置 ADT 的早期步骤并开始开发,请从developer.android.com/sdk/index.html
下载 ADT 捆绑包,并按照developer.android.com/sdk/installing/bundle.html
的步骤进行设置。
在下一章中,我们将探讨 ADT 环境中的工具,这些工具简化了开发过程。
总结
在本章中,我们学习了如何安装 Eclipse Juno(集成开发环境)、Android SDK 和测试平台。下一章将讨论 IDE 的重要元素,在我们创建一个新的 Android 应用项目之前。
第二章:IDE 的重要特性
本章介绍 Eclipse 和 ADT 环境中的几个重要特性,这些特性对于开发 Android 应用非常有用。它分为以下主题:
-
项目浏览器
-
代码编辑器
-
图形用户界面设计师
-
属性窗口
-
调试窗格
-
Dalvik 调试监控服务器(DDMS)
-
SDK 管理器
-
Android 虚拟设备管理器
-
运行应用
-
获取帮助
项目浏览器
项目浏览器是一个工具,用于查看项目下的所有文件夹和文件。通过双击项目,可以打开和编辑文件。当我们创建一个新项目时,将在第三章创建新项目中详细讨论,ADT 将自动创建所有这些默认的文件夹和文件,如下面的截图所示。根据项目,我们可能忽略或修改所有这些文件。以下是 Android 项目中默认文件夹和文件的简要说明:
项目浏览器
下表包含了项目树中可用的重要文件夹和文件的简要描述:
文件夹 | 功能 |
---|---|
/src |
这里存放 Java 代码 |
/gen |
自动生成 |
/assets |
放置字体、视频、声音等。更像是一个文件系统,也可以放置 CSS、JavaScript 文件等。 |
/libs |
外部库(通常为 JAR 格式) |
/res |
存放图像、布局和全局变量 |
/drawable-xhdpi |
针对超高性能设备(例如平板电脑、Galaxy SIII、HTC One X) |
/drawable-hdpi |
针对高性能手机(例如:SGSI、SGSII) |
/drawable-mdpi |
针对中等性能手机(例如:Galaxy W、HTC Desire) |
/drawable-ldpi |
针对低性能手机(例如:Galaxy Y、HTC WildFire) |
/layout |
所有屏幕布局的 XML 文件 |
/menu |
屏幕菜单的 XML 文件 |
/values |
全局常量 |
/values-v11 |
针对 Honeycomb(Android API 级别 11)设备的模板样式定义 |
/values-v14 |
针对 ICS(Android API 级别 14)设备的模板样式定义 |
AndroidManifest.xml |
定义应用的重要文件之一。这是 Android OS 为了运行应用而首先定位的文件。它包含应用的属性、活动声明和权限列表。 |
代码编辑器
这是编程的“烹饪”工具。Eclipse 代码编辑器(程序员喜欢拥有的)的几个重要特性是智能感知和错误标记(参考截图以了解)。代码补全建议将可用的对象、方法或变量整合到我们的代码中,而错误标记会在不编译代码的情况下立即通知任何语法错误。这些特性对于快速编程非常有帮助:
代码编辑器
代码编辑器的外观可以根据您的风格和偏好进行自定义。要更改编辑器环境(如背景色或代码字体样式),请在编辑器上右键单击并选择首选项,然后导航到常规 | 外观 | 颜色和字体。然后点击编辑来自定义,参考以下截图:
自定义代码编辑器的外观
还有一些其他的 XML 代码编辑器,在设计和开发过程中提供帮助。它们分为两种类型:基于 GUI 的,可以通过 GUI 界面操作,适合不习惯手动编辑 XML 代码的人;基于源代码的:可以手动编辑 XML 代码。以下列出了一些编辑器:
图形布局编辑器
使用拖放界面编辑和设计你的 XML 布局文件。布局编辑器还能渲染你的界面,让你在设计布局时预览效果。
Android 清单编辑器
使用简单的图形界面编辑 Android 清单。当你打开一个AndroidManifest.xml
文件时,会调用此编辑器。
菜单编辑器
使用简单的图形界面编辑菜单组和条目。当你打开一个声明了<menu>
的 XML 文件时(通常位于res/menu
文件夹中),会调用此编辑器。
资源编辑器
使用简单的图形界面编辑资源。当你打开一个声明了<resources>
标签的 XML 文件时,会调用此编辑器。
XML 资源编辑器
使用简单的图形界面编辑 XML 资源。当你打开一个 XML 文件时,会调用此编辑器。
图形用户界面设计师
这是界面设计师。它作为应用程序屏幕上的控件或小部件的 GUI 编辑器。此 GUI 设计师分为三个部分:调色板、配置选择器和屏幕布局预览,如下面的屏幕截图所示:
ADT 的 GUI 设计师
调色板包含了所有可以帮助我们设计界面的 GUI 控件(小部件)。可用的控件取决于我们在创建项目时选择的 API 级别。一些常见的控件有:按钮、文本字段、单选按钮、复选框、多媒体控件等等。
配置选择器
它让你决定你的应用视图在不同屏幕尺寸、方向、密度和主题下的外观。
屏幕布局设计师
它是一个放置物品并尝试不同设计的画布。它是一个设计工作区。同时,它还提供了屏幕在设备中可能出现的预览。
属性窗口
它帮助编辑小部件的属性。所有与小部件对应的属性都可以通过这个窗口可视化地查看和编辑。尽管可以通过编辑 XML 文件直接编辑属性,但这个 GUI 界面简化了操作。所有更改都会立即自动保存到 XML 文件中。以下截图展示了属性窗口:
属性窗口
调试窗格
在调试视图中,我们可以看到语法错误、警告、控制台消息、运行时错误、变量过渡(如果使用了断点)以及LogCat。 LogCat有助于追踪设备或模拟器内发生的任何活动。以下截图展示了列出所有代码问题(如警告或语法错误)的窗口:
问题警告或代码语法错误
下面的截图展示了一个来自 ADB 的控制台消息示例。作为 Java 开发者,我们可能想使用System.out.println()
来输出消息和对象值;这些在LogCat视图中显示,然而建议为此目的使用Log
类,因为我们可以过滤、打印不同颜色并定义日志类型。这可以是调试程序的一种方式,通过显示变量值或参数。要使用Log
,请导入android.util.Log
,并使用以下方法之一将消息打印到LogCat:
v(String, String) (verbose)
d(String, String) (debug)
i(String, String) (information)
w(String, String) (warning)
e(String, String) (error)
Android 调试桥接控制台(显示 ADB 活动)
LogCat用于查看 Android 系统的内部日志,如下截图所示。通过 ADB(Android 调试桥)追踪设备或模拟器内的任何活动非常有效。ADB 是一个将你的 PC 与虚拟设备或实际设备连接的工具。没有它,开发者不能直接将 APK 文件传输到 Android 设备/模拟器:
LogCat(追踪所有设备/模拟器活动的跟踪转储)
Dalvik 调试监控服务器(DDMS)
DDMS 是查看模拟器/设备活动的必备工具。要在 Eclipse 中访问 DDMS,请导航到窗口 | 打开透视图 | 其他,然后选择DDMS。默认情况下,它可在 Android SDK 中找到(位于android-sdk/tools
文件夹中的ddms
文件)。从这个透视图,以下方面可用:
-
设备:连接到 ADB 的设备和 AVD 列表
-
模拟器控制:它帮助执行设备功能
-
LogCat:它查看实时系统日志消息
-
线程:它给出了 VM 中当前运行线程的概念
-
堆:它显示应用程序的堆使用情况
-
分配追踪器:它提供有关对象内存分配的信息
-
文件资源管理器:它浏览设备文件系统
下图展示了 DDMS 的重要方面:
Dalvik 调试监控服务器(DDMS)
SDK 管理器
SDK 管理器是用于更新安卓 SDK 和管理安卓操作系统映像、文档和 API 下载的工具。图标如下截图所示:
SDK 管理器图标
如截图所示,接下来出现的屏幕有一个非常长的列表。我们需要明确我们需要哪个 API 级别,并据此选择,因为下载可能需要相当长的时间,这取决于互联网速度。如果不确定,那么选择最新的 API 级别。
展开我们想要发布的 API 级别并检查 SDK 平台。这次下载包括相应级别的 API 和安卓操作系统映像。默认情况下,系统映像是基于 ARM 架构的。然而,为了在 Intel 架构机器上更快地运行安卓操作系统映像,只需勾选Intel Atom x86 系统映像选项。
如果需要从样本学习,请勾选SDK 的样本。如果你的应用程序需要整合谷歌特殊 API(如谷歌地图),那么你可能需要下载谷歌 API。列表的其余部分是关于特定设备的 API。除非你打算为特定设备优化你的应用程序,否则不要下载。
完成必要 API 的选择后,点击安装包按钮。如果在下载过程中遇到连接重置问题,请导航到工具 | 选项。取消勾选强制使用 https://...源,改为使用http://...获取,然后重试:
安卓 SDK 管理器窗口
安卓虚拟设备管理器
安卓虚拟设备是在你的计算机上运行的虚拟移动设备(模拟器)。模拟器允许你在不使用物理设备的情况下测试安卓应用程序。尽管这并不是最佳的测试方法,因为它只是模仿设备,但至少在你负担不起实际安卓设备的情况下,你还有东西可以测试。
当模拟器运行时,你可以像操作真实移动设备一样与模拟的移动设备互动,不同之处在于你使用鼠标指针触碰触摸屏,并且可以使用某些键盘按键来调用设备上的特定按键。
安卓模拟器模仿了典型移动设备的所有硬件和软件功能,唯独不能进行实际电话通话。它提供了多种导航和控制按键,你可以使用鼠标或键盘“点击”来为你的应用程序生成事件。它还提供了一个屏幕,显示你的应用程序以及任何其他正在运行的安卓应用程序。对于某些功能,我们可能需要了解热键,具体信息可以在developer.android.com/tools/help/emulator.html#KeyMapping
找到。
点击如下截图所示的按钮,打开 Android SDK 和AVD 管理器窗口。AVD即Android 虚拟设备:
AVD 图标
AVD 管理器如下截图所示。首先,点击新建…来设置一个新的模拟器,如截图所示。输入一个名称(例如,nexus
),选择一个目标(确保为所选目标下载了 Android OS 系统镜像),为了简单起见选择设备,其他字段将会自动填充。如果我们想要不同的设置,也可以进行编辑。同时,选择CPU为ARM (armeabi-v7a),然后点击创建 AVD:
创建新的 AVD
点击已经创建好的新 AVD,然后使用启动按钮启动 AVD。使用默认设置,并点击启动按钮。
如果我们的处理器和内存规格较低,你会注意到它的模拟器启动非常慢。我想建议你至少有 3GB 的 RAM 来使其更快。
等待直到左侧屏幕显示如下截图所示的带有图标的漂亮图片。左边的组件是你的设备(智能手机)屏幕,而右边的组件是物理智能手机键盘:
Android 模拟器
运行应用程序
没有错误的项目将能够被执行并发送到 AVD。要运行一个项目,请点击如下所示图片中的运行按钮。如果你的系统已经运行了几个模拟器,Eclipse 将会询问你要使用哪个版本的模拟器:
运行应用程序按钮
获取帮助
-
在菜单中选择帮助,然后选择搜索
-
Eclipse 帮助:
help.eclipse.org/juno/index.jsp
-
Android 开发者官方参考:
developer.android.com
-
ADT 更新:定期从菜单中检查 ADT 更新,帮助 | 检查更新
-
更多关于 DDMS 的信息:
developer.android.com/tools/debugging/ddms.html
总结
在本章中,我们讨论了 Eclipse 和 ADT 中提供的几个重要工具,如项目浏览器、代码编辑器、图形用户界面设计器、属性窗口、调试窗格、Dalvik 调试监控、SDK 管理器、AVD 管理器和运行应用程序设施。下一章将讨论如何创建一个新的 Android 应用程序项目。
第三章:创建新的 Android 项目
本章将演示如何使用按钮和文本字段创建一个新的具有简单交互的 Android 应用。我们还将编写交互代码,编译并在模拟器/实际设备上运行应用。为了说明本章内容,我们将创建一个名为 HelloU 的简单项目。
-
创建新的 Android 应用项目字符串资源
-
使用图形布局设计器
-
字符串资源
-
XML 布局编辑器
-
通过源代码编辑器实现小部件的交互
-
提示信息
-
在模拟器上运行应用
-
在 Android 设备上运行应用
-
获取帮助
提示
下载示例代码
你可以从你在www.packtpub.com
的账户下载你所购买的所有 Packt 图书的示例代码文件。如果你在其他地方购买了这本书,可以访问www.packtpub.com/support
注册,我们会将文件直接通过电子邮件发送给你。
创建一个新的 Android 应用项目
在 Eclipse 中创建新的 Android 项目,选择文件 | 新建 | 项目。将出现新的项目窗口,然后从列表中选择Android | Android Application Project。点击下一步按钮。
-
应用名称:这是你的应用程序的名称,它将与应用启动图标并排显示。选择一个与你的应用相关的项目名称。
-
项目名称:这通常与应用名称相似。避免与 Eclipse 中现有项目的名称相同,这是不允许的。
-
包名称:这是应用程序的包名称。如果我们希望发布到 Google Play 应用商店,它将作为 ID。通常,如果我们有一个域名(因为这是唯一的),它将是域名反转后跟应用程序名称,并是一个有效的 Java 包名称;否则,我们现在可以是任何名称,并在发布前进行重构。
android:minSdkVersion
是一个指定应用运行所需最低 API 级别的整数。如果不确定,可以保持默认选择。
例如,你可能将应用设置为android:minSdkVersion="7"
。这个设置将保证你的应用在 Android Éclair(2.1)或更高版本的设备上运行,但不会在更低版本上运行。
targetSdkVersion
是你关注的目标设备。假设你的应用有android:minSdkVersion="16"
,这意味着应用可以利用 Android Jelly Bean 的所有功能。但是,请记住,如将应用移动到 SD 卡和原生 Unicode 支持等功能在 Android(2.1)Eclair 中是不支持的。尽管这些功能从 API 级别 8(Android 2.2/Froyo)和级别 11(Android 3.0/Honeycomb)开始提供,但它们不能在更低版本的 Android 上使用。
请记住,你的targetSdkVersion
必须等于或高于minSdkVersion
。否则,这样做没有太大意义。
点击下一步移到下一步:
创建一个新的 Android 项目
这是配置你的启动图标的窗口。启动图标是在主屏幕或应用抽屉中出现的图标。这是你应用的一个重要方面,因为它将代表你的应用。为此,你可以使用 ADT 中预定制好的文本和图标形状的图标创建向导。将前景设置为文本,提供字母U
作为文本,选择圆形作为图标形状,并根据以下截图调整你的颜色偏好。这个向导将创建一个简单的图标,并提供 ldpi(36x36 像素)、mdpi(48x48 像素)、hdpi(72x72 像素)和 xhdpi(96x96 像素)的启动图标。创建不同大小的图标是为了适应各种具有不同屏幕尺寸和分辨率配置的设备。点击下一步继续:
启动图标创建器
在如下截图所示的窗口中选择BlankActivity,然后点击下一步:
选择空白活动
下一个窗口将出现以输入MainActivity
的名称,如下截图所示,然后点击完成按钮:
字符串资源
通常,对于 Android 应用来说,将字符串值存储在 XML 文件中以便于用户界面引用是一种做法,这是因为移动应用具有国际化的特性。因此,最好提供多种语言选项。然而,这一做法是可选的,如果你愿意,也可以直接分配字符串。
字符串资源文件以 XML 格式存在,可以通过项目树在res/values/strings.xml
中找到。这些字符串资源还可以用来存储颜色信息、整型数组等。
现在,点击添加按钮新增一个字符串值,在名称框中提供变量名和字符串的值。按Ctrl + S保存更改。例如,在以下截图中,创建了一个新的字符串变量hello_u
,其值为Hello,:
添加一个新的字符串值
根据下表添加另外两个字符串值。这些字符串将用作小部件的标题:
字符串变量 | 值 |
---|---|
s_tvName |
你的名字: |
s_btnDisplay |
显示名字! |
如果你注意到了,我们使用s_
来表示它是一个来自资源的字符串变量,tv
表示TextView
,btn
表示按钮。请记住,这些约定不是固定的,你可以使用你自己的偏好。
新创建的字符串值将被保存在 string.xml
文件中。通过点击如下截图所示的红箭头指向的标签,可以查看 XML 代码:
string.xml 代码文件
使用图形布局设计器
下一个练习是添加一个文本标签、一个文本框和一个按钮。这些元素在 Android 中被称为控件,其类名为 TextView
、EditText
和 Button
。我们将不详细介绍这些类,最重要的是我们可以将这些控件应用到我们的应用中。
要打开这个布局,请从项目浏览器中双击 res/layout/activity_main.xml
文件。
在应用屏幕的左侧,你会看到 Palette(调色板)。浏览 Form Widgets(表单控件),其中有几个控件包括 TextView
。点击并将 TextView
控件拖到应用屏幕上。将控件 ID 更改为 "@+id/tvName"
,并确保按 Enter 键确认更改并将其保存到 XML 文件中。"@+id/"
是 ADT 表示法,表示必须创建新的 ID 并将其分配给控件。
之后,将 Text 属性设置为指向字符串资源中定义的值,s_tvName
。可以通过点击每个属性右侧带有三个点的按钮来完成此操作。按下 Ctrl + S 保存更改,确保更改出现在 XML 文件中:
更改 TextView 的标题
接下来要添加的控件是带有 Id txtName
的 EditText,关联标签为 Your name: 以接受用户输入,如下截图所示:
添加一个 EditText
添加另一个控件,按钮,指定 ID btnDisplay
并关联标签为 Display Name,如下所示,并将其水平扩展到整个屏幕。你可以通过点击并拖动控件边缘的蓝色调整标记来使用调整大小的功能:
添加一个 Button
XML 布局代码编辑器
代码编辑器是更改布局属性的另一种方式。如果你有 XML 的先验知识,我们建议直接更改此代码。这实际上是一段简单的 XML 代码。要直接访问此代码,只需点击布局编辑器底部的 activity_main.xml
,如下截图所示:
访问 XML 布局代码编辑器
通过源代码编辑器进行控件交互
我们之前设计的布局不需要自动相互交互;让我们实现这一点。简单来说,当我们执行项目时,点击应用上的按钮不会触发任何操作。我们需要添加交互的代码。
我们试图实现的是当用户点击 显示名称! 按钮时,应用将捕获 TextView
内的任何文本,并生成一个简单的弹出窗口来显示你的名字。
为了达到我们的目标,让我们随意操作,进入 src
目录,双击 package
文件夹,再次双击文件 MainActivity.java
。这个 Java 文件将包含加载 XML 文件 main_activity.xml
的布局代码,以创建一个 UI。以下是由 ADT 提供的默认代码。
你会在第一行看到包名和导入项目的几个类。第六行的代码是主类声明,它继承了 Activity
类。第八行的 onCreate
方法是应用启动时第一个被调用的方法。setContentView(R.layout.activity_main)
是根据之前设计的主屏幕初始化屏幕布局的命令。第 13 行的创建屏幕菜单的方法将在 第五章 添加单选按钮、复选框、菜单和偏好设置 中讨论。
package net.kerul.HelloU;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
public class MainActivity extends Activity{
//First method called when App starts
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
// loads Screen menu
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main,
menu);
return true;
}
}
为了提供按钮交互,我们需要在主类头部添加实现 OnClickListener
。
public class MainActivity extends Activity implements OnClickListener {
在代码的导入部分,添加这一行:
import android.view.View.OnClickListener;
现在,初始化将在过程中涉及的所有小部件。在主类头部之后,立即添加小部件的成员声明。
public class MainActivity extends Activity implements OnClickListener{
private EditText txtName;
private Button btnDisplay;
…
由于 EditText
和 Button
也是需要从 Android API 导入的另一个类,所以在导入部分添加几行。
import android.widget.Button;
import android.widget.EditText;
提示
在 Eclipse 中,你不需要记住所有需要导入的类和包的名称。只需将光标(插入符号)放在类上,按 Ctrl + Shift + O。IDE 将帮助你包含相关的包或者将鼠标指向其他类,会弹出一个菜单,选择导入该类。
从 Android API 导入类的菜单
下一步是在 MainActivity.xml
文件中将代码与布局设计相链接。这是必要的,因为 ADT 正在采用 MVC(模型-视图-控制器)开发方法。这意味着屏幕布局与代码分离,以提高项目的可维护性。
基本上,在通过 setContentView
加载布局之后,你需要访问隐藏在该布局中的这些小部件。这时 findViewById()
就派上用场了。
txtName=(EditText)findViewById(R.id.txtName);
btnDisplay=(Button)findViewById(R.id.btnDisplay);
按钮是动作;我们需要为按钮添加事件监听器。需要添加的行如下:
btnDisplay.setOnClickListener(this);
在这里,我们让 Activity 本身实现 onClickListener
。
为了处理任何点击事件,Java 需要包含一个特殊的方法。在这个方法内部,将执行任务。在我们的案例中,如果用户点击(或轻触)按钮(btnDisplay
),应用将提取文本字段(txtName
)的内容并在屏幕上显示。该动作可以按以下方式编码:
public void onClick(View arg0) {
if(arg0.getId()==R.id.btnDisplay){
String hellomsg="Hello, "+txtName.getText().toString();
Toast.makeText(this.getApplicationContext(), hellomsg,
Toast.LENGTH_SHORT).show();
}
}
View arg0
是触发动作的元素。arg0.getId()
是获取触发动作的小部件 ID 的方法。如果小部件 ID 是btnDisplay
,则执行捕获输入并在屏幕上显示的动作。
要获取文本字段小部件的字符串,请使用以下代码:
txtName.getText().toString();
Toast.makeText()
是在屏幕上显示简短消息的方法,我们将在下一节讨论它。
完整的代码将是:
package net.kerul.HelloU;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity implements OnClickListener{
private EditText txtName;
private Button btnDisplay;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txtName=(EditText)findViewById(R.id.txtName);
btnDisplay=(Button)findViewById(R.id.btnDisplay);
btnDisplay.setOnClickListener(this);
}
public void onClick(View arg0) {
if(arg0.getId()==R.id.btnDisplay){
String hellomsg="Hello, "+txtName.getText().toString();
Toast.makeText(this.getApplicationContext(), hellomsg,
Toast.LENGTH_SHORT).show();
}
}
}
Toast 消息
这是一种常见的做法,用于弹出消息框以通知用户。这种通知是一种不需要用户回答或反馈的通知类型。
Toast.makeText(this.getApplicationContext(), hellomsg,
Toast.LENGTH_SHORT).show();
Toast.makeText()
包含三个参数,分别是应用上下文、消息和显示时长。
-
应用上下文是当前要显示消息的屏幕
-
要显示的消息是字符串
-
显示时长包括消息显示的短时间或长时间,必须是
Toast.LENGTH_*
常量之一
下面的截图中的箭头指向一个 Toast:
Toast 的一个示例
在模拟器上运行应用
在模拟器中运行HelloU应用需要你先启动模拟器。启动一个与你的目标平台相匹配的 Android 版本的模拟器。一旦模拟器完全加载,我们就可以编译并运行应用。
在项目资源管理器上点击HelloU项目(这是为了激活项目)。在 Eclipse 菜单中导航到运行,选择运行或按快捷键Ctrl + F11。选择作为 Android 应用运行,并按下Enter。等待几秒钟,查看你的模拟器。HelloU应用很快就会显示,如下面的截图所示。输入你的名字,点击显示名字!按钮,屏幕底部将出现带有输入名字的 Toast 消息:
在模拟器中运行的 HelloU 应用
在 Android 设备上运行应用
要在真实设备上运行和部署,首先安装设备的驱动程序。这会根据设备型号和制造商而有所不同。
以下是一些你可以参考的链接:
-
仅适用于 Google Android 设备
developer.android.com/sdk/win-usb.html
。
确保安卓手机通过 USB 线连接到电脑。要检查手机是否已正确连接到你的电脑并处于调试模式,请切换到 DDMS 视角。
在 DDMS 中显示的安卓手机。
如果一切顺利,运行应用。注意会弹出一个窗口,让你选择模拟器和一个真实的安卓设备;选择安卓设备。几秒钟后,应用将在安卓手机上运行。
在实际安卓设备上运行 HelloU 应用。获取帮助
以下是一些关于如何使用 Eclipse 和 ADT 的参考资料。你可以花些时间阅读文档和教程以获取更新。在stackoverflow.com上阅读教程和讨论是学习这些工具的便捷方式之一。
-
在菜单中选择帮助,然后选择搜索。
-
Eclipse 帮助:
help.eclipse.org/juno/index.jsp
-
安卓开发者官方参考文档:
developer.android.com
-
ADT 更新:定期从菜单中的帮助 | 检查更新来检查 ADT 更新。
-
更多关于 DDMS 的信息:
developer.android.com/tools/debugging/ddms.html
总结
恭喜你!现在你拥有了自己的安卓应用。你已经设计了屏幕布局,添加了标签、文本字段和按钮。简单的交互性让你了解了如何开发安卓移动应用。在下一章中,我们将添加更多小部件并学习开发涉及多个屏幕的更复杂应用。
第四章:融入多媒体元素
本章将讨论如何在项目中融入多媒体元素并在应用中处理多个屏幕。我们将向读者展示如何添加图片、声音和 HTML 页面。我们将通过一个名为SimpleNumb3r5
的项目来讨论以下主题:
-
构建布局
-
添加图像资源
-
插入 ImageView
-
插入 ImageButtons
-
ImageButton 和事件处理
-
添加音频和支持多屏幕
-
在 WebView 中插入 HTML
-
使用 Intent 和 Activity
-
在清单文件中添加新的活动
-
最终产品——运行、部署和测试应用
为了本章内容,我们需要一个新项目,该项目将涵盖从 Android 2.1(API 级别 7)到最新版本的设备。因此,将android:minSdkVersion
设置为 7,android:targetSdkVersion
设置为 16。
图标和其他资源可以在可下载的源代码中找到(参考本书前言中提到的下载提示)。在开发此应用之前,请下载这些材料。我们不想让你在做图形设计时感到痛苦。
新应用选择的名称为SimpleNumb3r5
,如下截图所示。如果你好奇为什么我们选择 Android 2.1,这是因为我们希望扩大设备覆盖范围:
创建一个名为 SimpleNumb3r5 的新 Android 项目
我们在资源材料中提供启动图标,并在图像文件字段中提供名为ic_launcher-web.png
的图片,如下截图所示。这是此应用的专用标志。如果你想要一个不同的标志以适应你的应用,欢迎你亲自设计。使用这个向导,图标启动器将被准备到适应xhdpi
、hdpi
、mdpi
和ldpi
格式的相应 drawable 文件夹中。
创建启动图标
如下截图所示的下一个屏幕是提供应用程序名称的。这可以是任何对应用有合适意义的字符串。布局名称将自动为您创建,可以根据您的喜好进行更改。选择导航类型为无,因为这与我们的应用开发无关。
选择空白活动
下面的截图是正在开发的应用的模拟图。我们有一个主要区域用于显示数字零到九的图片和拼写。屏幕底部的行是导航栏,用户可以通过它导航到上一个或下一个屏幕。带有扬声器的按钮是让用户听数字发音的。带有小写字母i的按钮是显示信息屏幕的图标。
-
项目标题(默认显示)。
-
图像编号位置。这一行由三个单元格合并而成。
-
底部行包括上一个、信息、播放声音和下一个按钮。
主屏幕模拟图
添加 TableLayout
我们的项目将包含一个 TableLayout,内部有两个 TableRow。默认情况下,当你添加 TableLayout 时,IDE 将包含四组 TableRow。使用 XML 代码编辑器删除两行,上一个应用程序模拟图可以提供一些指导以删除不使用的行。调整 TableLayout,使其利用屏幕布局的所有空间,如下一个截图所示:
插入 TableLayout
添加图像资源
通过 Windows 文件管理器将第四章补充文件中提供的图像复制到res/drawable-hdpi
文件夹中,如下一个截图所示。在此练习中,我们只为hdpi
drawable 提供图像资源。相应地准备xhdpi
、mdpi
和ldpi
的所有适当资源总是一个好习惯。别忘了 Android 设备中有许多屏幕尺寸变种。目前我们也没有考虑平板尺寸设备的资源。
drawable 的资源
然后进入你的项目资源管理器(在 Eclipse 中),右键点击res/drawable-hdpi
并选择刷新。以下截图显示了图像资源复制后drawable-hdpi
文件夹的外观:
drawable 的资源
添加 ImageView
如前一个截图所示,我们的应用程序有一个图像 0,它占据了整个屏幕,为了实现这一点,让我们在 TableLayout 的第一行添加一个 ImageView。使用 drawable 文件夹中的 no0 图像作为初始图像(零是要显示的第一个数字)。调整 ImageView 的宽度和高度以填满屏幕。
向应用屏幕添加 ImageView
平均分配权重(指定布局中额外的空间分配给视图的比例),以使小部件居中。使用以下截图中的按钮调整 ImageView 到屏幕中心。在 ImageView 处于激活(选中)状态时进行此操作:
平均分配权重
添加 ImageButton
TableLayout 的第二行用于导航按钮(上一个和下一个)以及播放声音按钮。对于这种类型的应用程序,ImageButton 更具吸引力。创建 ImageButton 时,系统会要求你选择图像。对于第一个按钮,使用 drawables 中的prev图像。第二个是sound,最后一个是next。这些按钮需要逐一添加,如下一个截图所示:
添加 ImageButton
激活(选择)其中一个按钮并平均分布,如下面的截图所示。这是为了确保所有按钮均匀分布在屏幕宽度上。
平均分配 ImageButton 的权重
如果你愿意,可以更改屏幕的背景。已经为你准备了一个背景图像;它在 drawables 文件夹中,名为bglight。通过点击应用屏幕上的应用标题/标志来激活主布局。点击属性右侧的三点按钮来更改背景属性。稍后,你可以添加btninfo按钮来显示应用信息。
分配小部件的 ID
基本上有一个 ImageView 和三个 ImageButton。要更改 ImageView 的 ID,选择它并转到右侧的小部件属性。点击Id属性上的三点按钮。将 ImageView 的 ID 更改为imagenumber,如下面的截图所示:
通过属性窗口更改小部件的 ID
之后,将所有按钮的 ID 更改为btnprevious、btninfo、btnsound和btnnext。以下表格可作为指南:
小部件 | ID |
---|---|
ImageView | imagenumber |
最左边的按钮 | btnprevious |
显示应用信息 | btninfo |
播放声音按钮 | btnsound |
最右边的按钮 | btnnext |
最后,你将得到如下所示的屏幕:
主活动的设计布局
以下 XML 代码可以通过Graphical Layout标签中的 XML 编辑器在activity_simple_numb3rs.xml
标签中找到:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bglight" >
<TableLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true" >
<TableRow
android:id="@+id/tableRow1"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1" >
<ImageView
android:id="@+id/imagenumber"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="img/no0" />
</TableRow>
<TableRow
android:id="@+id/tableRow2"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1" >
<ImageButton
android:id="@+id/btnprevious"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="img/prev" />
<ImageButton
android:id="@+id/btninfo"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="img/info" />
<ImageButton
android:id="@+id/btnsound"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="img/sound" />
<ImageButton
android:id="@+id/btnnext"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:src="img/next" />
</TableRow>
</TableLayout>
</RelativeLayout>
ImageButton 和处理事件
在这里,我们将编写 ImageButton 的点击事件。打开src/net.kerul.simplenumb3r5/SimpleNumb3r5.java
中的 Java 源代码。这里,我们将讨论主要活动类,它将使用以下代码提供屏幕导航:
public class SimpleNumb3r5 extends Activity implements OnClickListener
主类通常继承Activity
类,并实现OnClickListener
以启用小部件交互。
主要变量声明如下:
//initialize all widgets
private ImageView imagenumber;
private ImageButton btnprevious, btninfo, btnsound, btnnext;
//define variables to track screen number, start from 0
private int screennumber=0;
//define a sound controller
private MediaPlayer mp;
//define an array for the sound files
private String[] soundfile={"0.mp3","1.mp3","2.mp3","3.mp3",
"4.mp3","5.mp3","6.mp3","7.mp3","8.mp3","9.mp3"};
小部件对象是用于显示图像数量的容器imagenumber
,以及按钮btnprevious
、btnsound
和btnnext
。
screennumber
是跟踪当前屏幕位置的变量;最初它被赋予 0 的值,因为我们有一个从零(0)开始的数字列表。
声音控制器对象名为mp
,字符串数组soundfile
是零到九的口语数字录音列表。
onCreate
方法是在其中初始化所有小部件并将它们在视图中连接在一起的地方,如下所示:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_simple_numb3r5);
imagenumber=(ImageView)findViewById(R.id.imagenumber);
//create the object for the button
btnprevious=(ImageButton)findViewById(R.id.btnprevious);
//this button will initially be disabled
btnprevious.setEnabled(false);
//add listener to the button
btnprevious.setOnClickListener(this);
btninfo=(ImageButton)findViewById(R.id. btninfo);
btninfo.setOnClickListener(this);
btnsound=(ImageButton)findViewById(R.id.btnsound);
btnsound.setOnClickListener(this);
btnnext=(ImageButton)findViewById(R.id.btnnext);
btnnext.setOnClickListener(this);
}//end onCreate
接下来,我们有onClick
方法来处理导航交互。这里的基本操作是如果screennumber
为 0,则禁用btnprevious
按钮,如果screennumber
大于 0 则启用。如果screennumber
的值为 9,则禁用btnnext
,如果小于 9 则启用。这是为了防止用户尝试访问小于 0 或大于 9 的值时出现运行时错误。btnsound
的值目前被忽略;我们将在处理声音(即播放声音/音频)时再讨论。
//this method is to handle button click
public void onClick(View arg0) {
//when btnprevious is clicked
if(arg0.getId()==R.id.btnprevious){
screennumber--;// Decrement 1 to the screennumber
changeNumber(screennumber);
if(screennumber==0){
// Disable previous Button
btnprevious.setEnabled(false);
}else{
// Enable back disabled Button.
btnprevious.setEnabled(true);
}
changeNumber(screennumber);
btnnext.setEnabled(true);
}
//when btnnext is clicked
else if(arg0.getId()==R.id.btnnext){
screennumber++;//add 1 to the screennumber
changeNumber(screennumber);
if(screennumber==9){
Disable no screen available next
btnnext.setEnabled(false);
}else{
/ Only prevoius screen available
btnnext.setEnabled(true);
}
changeNumber(screennumber);
btnprevious.setEnabled(true);
}
//when btnplay is clicked
else if(arg0.getId()==R.id.btnsound){
//playSound - will implement later
}
else if(arg0.getId()==R.id.btninfo){
//display info will implement later
}
}//end onClick
还有一种方法可以切换数字的图片。R.id.imagefile
是实际可绘制图像资源的表示。因为我们总共有 10 张图片,而R.id
返回的是int
类型,所以我们可以按照如下方式使用 switch case 10 次:
//this method is to change the number that appears on the screen
// after the navigation button is clicked
// as R.id retuns int so we use switch
private void changeNumber(int screen){
switch (screen){
case 0: imagenumber.setImageResource(R.drawable.no0);
break;
case 1: imagenumber.setImageResource(R.drawable.no1);
break;
case 2: imagenumber.setImageResource(R.drawable.no2);
break;
case 3: imagenumber.setImageResource(R.drawable.no3);
break;
case 4: imagenumber.setImageResource(R.drawable.no4);
break;
case 5: imagenumber.setImageResource(R.drawable.no5);
break;
case 6: imagenumber.setImageResource(R.drawable.no6);
break;
case 7: imagenumber.setImageResource(R.drawable.no7);
break;
case 8: imagenumber.setImageResource(R.drawable.no8);
break;
case 9: imagenumber.setImageResource(R.drawable.no9);
break;
}
}//end changeNumber
添加音频
在进行这个练习之前,将所有声音资源复制到assets
文件夹中。你可以通过文件管理器
将所有 mp3 文件复制到assets
文件夹中,如下面的截图所示:
将 MP3 文件复制到 assets 文件夹。
在onClick
方法中为btnsound
添加代码。添加以下几行,以便当点击btnplay
按钮时,执行名为playSound()
的方法。这个方法将接收一个字符串参数,作为要播放的声音文件名。
soundfile
数组变量是存储 mp3 文件名列表的变量,而screennumber
表示屏幕上的当前数字。
//when btnplay is clicked
else if(arg0.getId()==R.id.btnsound){
//call the method playSound
playSound(soundfile[screennumber].toString());
}//end btnsound clicked
下一个重要的方法是playsound
方法。这个方法将播放一个 mp3 声音文件。soundname
参数是包含位于 Android 项目的assets
文件夹中的声音文件名的字符串。
public void playSound(String soundName){
Boolean mpPlayingStatus;
try{//try to check MediaPlayer status
mpPlayingStatus=mp.isPlaying();
}
catch (Exception e){
mpPlayingStatus=false;
}
//if the MediaPlayer is playing a sound, stop it to play new voice
if(mp.isPlaying()){
mp.stop(); //stop the sound
mp.release(); //remove sound from the memory
}
else{
try{
mp = new MediaPlayer();
AssetFileDescriptor afd = getAssets().openFd(soundName);
//set the sound source file
FileDescriptor fd = afd.getFileDescriptor();
mp.setDataSource(fd);
mp.prepare(); // prepare for playback
mp.start(); //play the sound
}//try block
catch(IOException e) {
//display the error message in debug
Log.i("Error playing sound: ", e.toString());
}
}
}//end playSound
以下是涉及到的变量和过程的解释:
-
try…catch 块
: 这是一个异常处理程序,其目的是包围可能抛出异常的代码。在本例中,异常是尝试使用MediaPlayer
播放声音文件时捕捉任何问题。如果你注意,如果某个代码执行导致异常,将执行 catch 块语句。 -
mp
是从MediaPlayer
类实例化的对象。-
isPlaying()
: 检查MediaPlayer
是否正在播放,True
表示正在播放,false
表示未播放。 -
setDataSource()
: 设置将要使用的数据源。在本例中,数据源是FileDescriptor
。 -
prepare()
: 同步准备播放器进行播放。 -
play()
: 播放声音文件。 -
stop()
: 停止当前正在播放的声音。 -
release()
: 从内存中释放声音。
-
-
afd
是从AssetFileDescriptor
类实例化的变量。-
getAssets()
: 通过AssetManager
API 从assets
文件夹中获取底层资源。 -
openFD()
: 打开String
参数中指定的文件。 -
getFileDescriptor()
: 返回可以用来读取文件中数据的FileDescriptor
数据源。 -
getStartOffSet()
: 返回此资产条目数据开始的字节偏移量 -
getLength()
: 返回此资产条目数据的总字节数
-
在应用中添加另一个屏幕
这个练习是在SimpleNumb3r5
应用中添加一个信息屏幕。关于开发者、电子邮件、Facebook 粉丝页面和其他信息将在下一个屏幕上显示。由于屏幕包含大量文本信息,包括几幅图片,因此我们在这里使用 HTML 页面作为我们的方法:
-
现在,创建一个活动类来处理新屏幕。打开
src
文件夹,右键点击包名(net.kerul.SimpleNumb3r5
),选择New | Other...。在选项中,选择添加新的 Android 活动,然后点击Next按钮。接着,选择一个空白活动并点击Next。 -
将活动名称设置为Info,如下截图所示,向导将建议屏幕布局为info_activity。点击Finish按钮。
创建一个名为 Info 的新活动
-
将出现一个新的空白屏幕布局。移除默认的
HelloWorld
TextView。在Palette面板中,打开名为Composite
的文件夹。 -
点击并拖动 WebView 小部件。将 WebView 的 ID 更改为
webinfo
。此布局将保存在info_activity.xml
文件中。添加一个 WebView 小部件
在 WebView 中添加 HTML
使用您喜欢的网页编辑器创建一个 HTML 页面,或者您可以重复使用提供的资源中的 HTML 页面(在assets
文件夹中,文件名为info.html
)。如下截图所示的 HTML 页面是一个包含应用信息的简单 HTML 页面。如果您发现 HTML 过于简单,请添加您自己的信息。在这个练习中,我们将把 HTML 页面和资源放在assets
文件夹中,因此在继续之前,请将 HTML 页面的所有相关材料复制到assets
文件夹中。
info.html
中的 HTML 页面
接下来是编辑位于src/net.kerul.simplenumb3r5
文件夹中的Info.java
源代码。在现有模板中添加以下代码:
package net.kerul.simplenumb3r5;
import android.app.Activity;
import android.os.Bundle;
import android.webkit.WebView;
public class Info extends Activity {
private WebView webinfo;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_info);
webinfo=(WebView)findViewById(R.id.webinfo);
//provide the URL path pointing to info.html
webinfo.loadUrl("file:///android_asset/info.html");
}
}
让我们理解一下添加到上述模板中的以下代码行:
-
setContentView(R.layout.activity_info)
:R.layout.activity_info
是指之前创建的布局。 -
webinfo.loadUrl("file:///android_asset/info.html")
: 这是加载特定 URL 的 HTML 页面的方法。指向assets
文件夹内 HTML 文件的路径是file:///android_asset/info.html
。这个路径在真实设备上找不到,但它提供了访问app asset
文件的方法。
意图和活动
意图是对将要执行的操作的抽象描述。更具体地说,它是一个异步调用,允许应用程序从其他 Android 组件(例如服务/活动)请求功能。它可以与startActivity()
命令一起使用来启动一个活动。在SimpleNumb3r5.java
中的先前代码是此应用程序的主活动(或类)。我们刚刚在文件Info.java
中创建了第二个活动(类)。为了让第二个活动出现,必须使用意图来启动它。
我们决定使用按钮btninfo
作为触发器来调用第二个活动。再次打开文件SimpleNumb3r5.java
,并添加以下代码以调用另一个活动。这些代码必须添加到btninfo
按钮的onClick
方法中。注意,这里创建了一个名为 info 的Intent
实例。主类能够使用startActivity()
方法调用第二个类。Info.class
参数指的是第二个类。
else if(arg0.getId()==R.id.btninfo){
//invoke the Info activity
Intent info = new Intent(this, Info.class);
startActivity(info);
}Adding Activity in Manifest file
为了通过Intent
调用第二个类,需要修改Manifest.xml
文件。但是,你会注意到从版本 20 开始,Android 开发工具包已经自动完成了这一步。如果AndroidManifest.xml
中缺少以下代码,请手动添加:
<activity
android:name=".Info"
android:label="@string/title_activity_info" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category
android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
如果你需要在 WebView 中显示来自互联网的网页,你必须在AndroidManifest.xml
中的<application>
标签上方添加以下这行代码来声明用户权限:
<uses-permission android:name="android.permission.INTERNET" />
最终产品的运行和测试
在经历了所有这些过程之后,在模拟器中运行应用程序,你将得到以下屏幕:
SimpleNumb3r5
实战
概述
在本章中,我们探索了一种简单的方法来整合多个多媒体元素,如图片、HTML 页面和语音。最新的 SDK 比之前的任何版本都要用户友好。
在下一章中,我们将了解更多关于不同小部件的知识,如菜单、复选框、单选按钮,以及如何添加偏好设置屏幕。
第五章:添加单选按钮、复选框、菜单和首选项
你是否足够兴奋?如果没有,你应该感到兴奋;我们已经完成了一半,准备探索更多常用并且在任何应用程序中都有重要意义的组件。本章将要介绍的是向应用程序添加菜单、复选框、单选按钮和首选项。我们将使用这些组件并创建DistanceConverter
应用程序。该应用程序的主要目标是转换输入的公里/米到英里/英尺和码。以下是我们在本章中涵盖的步骤,以成功创建DistanceConverter
应用程序:
-
创建项目:
DistanceConverter
-
添加单选组.单选按钮
-
添加复选框
-
添加菜单
-
定义字符串
-
定义首选项屏幕
-
连接
-
绑定菜单和首选项
-
从首选项获取值
-
运行应用程序
创建新项目
DistanceConverter
应用程序将允许用户输入公里/米,并将它们同时转换为英里、英尺和码。我们已经在之前的章节中介绍了如何创建新项目,因此这里我们会简短说明。让我们通过导航到文件 | 新建 | 其他 | Android 应用程序项目来创建一个新项目。在相应的向导中输入以下表格中的合适数据:
属性 | 值 |
---|---|
应用程序名称 | DistanceCon |
项目名称 | DistanceCon |
包名称 | com.packt.ch05.distancecon |
模板 | BlankActivity |
活动 | MainActivity |
布局 | activity_main |
以下屏幕显示了一些根据前表在向导中填写的数据:
添加单选组、单选按钮和文本字段
安卓 SDK 提供了两种单选控件,用于同时使用,在任何给定时间只能选择一个控件。单选组(android.widget.RadioGroup
)用于封装一组单选按钮(RadioButton)控件,以达到此目的。
在我们添加单选组和单选按钮控件之前,让我们添加标签Distance
和文本字段以允许用户输入。打开activity_main.xml
文件,并添加以下条目:
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="14dp"
android:layout_marginTop="44dp"
android:text="@string/distance "
android:textAppearance="?android:attr/textAppearanceMedium" />
<EditText
android:id="@+id/distText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/textView1"
android:layout_alignBottom="@+id/textView1"
android:layout_toRightOf="@+id/textView1"
android:ems="10"
android:inputType="numberDecimal|numberSigned" />
让我们回到同一文件中添加单选组和单选按钮。添加以下条目:
<RadioGroup android:id="@+id/distanceRadioGp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/distText">
<RadioButton android:id="@+id/kmRadiobutton"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:checked="true"
android:text="@string/kmRadio">
</RadioButton>
<RadioButton android:id="@+id/metreRadioButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/metreRadio">
</RadioButton>
</RadioGroup>
我们已经设置为默认选中android:checked="true"
。完成这一步后,我们可能会看到一些错误,但不用担心,因为我们还没有定义这些字符串。
以下截图是我们在 XML 文件中添加上述代码后可能看到的内容:
添加复选框
我们将使用复选框(CheckBox)让用户一次性选择多种转换设施。要添加复选框,请在activity_main.xml
中添加以下代码。我们将有三个复选框,分别对应:英里、英尺和码;使用以下方法可以实现同样的效果:
<CheckBox
android:id="@+id/checkBoxFoot"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/textView1"
android:layout_below="@+id/checkBoxMile"
android:text="@string/toFoot">
</CheckBox>
<CheckBox
android:id="@+id/checkBoxYard"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/checkBoxFoot"
android:layout_below="@+id/checkBoxFoot"
android:text="@string/toYard">
</CheckBox>
<CheckBox
android:id="@+id/checkBoxMile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/checkBoxFoot"
android:layout_below="@+id/distanceRadioGp"
android:layout_marginTop="40dp"
android:text="@string/toMile">
</CheckBox>
还需添加一个按钮,点击它时启动转换:
<Button
android:id="@+id/calButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="60dp"
android:onClick="onClick"
android:text="@string/calc">
</Button>
结果屏幕应如下所示:
添加菜单
我们将从菜单中调用Preference
屏幕。实际上有三种不同的菜单可供选择:选项菜单、上下文菜单和弹出菜单。这里,我们将使用选项菜单来实现目的。在res/menu
下添加菜单,创建一个名为prefsetting.xml
的新文件。使用<item></item>
元素添加以下代码来添加菜单项:
<menu
<item android:id="@+id/menusettings"
android:showAsAction="never"
android:title="Preferences"
android:orderInCategory="100">
</item>
</menu>
菜单项的名称设置为android:title="Preferences"
。android:showAsAction
关键字表示项目应如何在操作栏中显示。更多菜单选项和属性请参考以下 URL:
定义字符串
在res/values标签下,打开strings.xml
并添加以下条目:
<string name="menu_settings">Settings</string
<string name="distance ">Distance</string>
<string name="kmRadio">Km</string>
<string name="metreRadio">Metre</string>
<string name="calc">Calculate</string>
<string name="toMile">Mile</string>
<string name="toFoot">Feet</string>
<string name="toYard">Yard</string>
完成此步骤后,之前的所有冗余错误应消失。
定义偏好设置屏幕
偏好设置是安卓应用的重要方面。它允许用户选择修改和个性化设置。偏好设置可以通过两种方式设置:第一种是在res/xml
目录中创建preferences.xml
文件,第二种是从代码中设置偏好设置。我们将使用前者,也就是更简单的方法,通过创建preferences.xml
文件,如下所示:
如果不存在,则创建xml
目录,并添加preferences.xml
文件。每个偏好设置都需要以下属性,如下表所示:
属性 | 描述 |
---|---|
android:key |
用于获取偏好设置值 |
android:title |
指定安卓标题 |
android:summary |
关于偏好设置的摘要 |
android:defaultValue |
可选,用于设置默认值 |
通常,有以下五种不同的偏好设置视图,如下表所示:
视图 | 描述 |
---|---|
CheckBoxPreference |
简单的复选框,返回 true/false |
ListPreference |
显示 RadioGroup,仅选中 1 个条目 |
EditTextPreference |
显示对话框编辑 TextView,返回字符串 |
RingTonePreference |
显示铃声的 RadioGroup |
PreferenceCategory |
带有偏好设置的类别 |
我们将在应用中使用CheckBoxPreference
、ListPreference
和PreferenceCategory
。现在在已创建的preferences.xml
文件中添加这些偏好设置视图。添加以下条目:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen >
<PreferenceCategory android:title="Set Default Converison ">
<CheckBoxPreference android:title="@string/convertToMile"
android:key="inputUserMile"
android:summary="@string/summaryMile"
android:defaultValue="false">
</CheckBoxPreference>
<CheckBoxPreference android:title="@string/convertToYard"
android:key="inputUserYard"
android:summary="@string/summaryYard"
android:defaultValue="false">
</CheckBoxPreference>
</PreferenceCategory>
<CheckBoxPreference android:title="@string/convertToFeet"
android:key="inputUserFt"
android:summary="@string/summaryFt"
android:defaultValue="false">
</CheckBoxPreference>
<PreferenceCategory android:title="@string/prefInputType">
<ListPreference android:title="@string/inputTypeList"
android:key="inputTypeKey"
android:summary="@string/userInputSummary"
android:entries="@array/inputEntry"
android:entryValues="@array/inputValues">
</ListPreference>
</PreferenceCategory
</PreferenceScreen>
这将导致出现很多错误,但是我们现在将通过定义字符串来解决这些问题。ListPreference
提供一个列表,并且只允许选择一个项目,因此包含android:entries,
和android:entryValues
取数组。现在我们将为同样的内容提供数组声明,为此,在res/values
下,如果不存在,创建arrays.xml
文件并添加以下条目:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="inputEntry">
<item >Distance in Km</item>
<item >Distance in Metre</item>
</string-array>
<string-array name="inputValues">
<item >1</item>
<item >2</item>
</string-array>
</resources>
在strings.xml
文件中定义以下字符串,这些字符串在preferences.xml
文件中使用。
<string name="prefInputType">Set Default Input Type</string>
<string name="userInputSummary">Distance provided for
calculation</string>
<string name="convertedSummary">Summary of Conversion</string>
<string name="convertToMile">Mile</string>
<string name="convertToYard">Yard</string>
<string name="convertToFeet">Foot</string>
<string name="summaryMile">Convert to Mile</string>
<string name="summaryYard">Convert to Yard</string>
<string name="summaryFt">Convert to Feet</string>
<string name="inputTypeList">Choose default distance supplied
</string>
现在我们已经定义了偏好设置屏幕,让我们做一些工作来展示它。偏好设置框架带有android.preference
的活动类。需要用我们的类覆盖PreferenceActivity
。在com.packt.ch05.distnacecon
包下创建一个UserSettings.java
类,并编写以下代码:
package com.packt.ch05.distancecon;
import android.os.Bundle;
import android.preference.PreferenceActivity;
public class UserSettings extends PreferenceActivity {
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
}
addPreferencesFromResources()
从preferences.xml
文件加载偏好设置屏幕。
进行连接
在定义并放置好所有东西之后,让我们开始通过将所有内容与主屏幕(主活动)连接起来进行一些操作。打开MainActivity.java
文件,现在让我们绑定东西。
按以下方式初始化小部件:
private EditText text;
private RadioButton rBtnKm;
private RadioButton rBtnMtr;
private CheckBox cBoxMile;
private CheckBox cBoxFt;
private CheckBox cBoxYd;
首先调用onCreate
方法来获取小部件的实例,如下所示:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text= (EditText)findViewById(R.id.distText);
rBtnKm=(RadioButton)findViewById(R.id.kmRadiobutton);
rBtnMtr= (RadioButton )findViewById(R.id.metreRadioButton);
cBoxMile = (CheckBox) findViewById(R.id.checkBoxMile);
cBoxFt = (CheckBox) findViewById(R.id.checkBoxFoot);
cBoxYd = (CheckBox) findViewById(R.id.checkBoxYard);
}
绑定菜单和偏好设置
我们通过getMenuInflater().inflate(R.menu.prefsetting, menu)
命令从资源文件prefesetting.xml
中指定我们之前定义的菜单,如下所示:
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if
it is present.
getMenuInflater().inflate(R.menu.prefsetting, menu);
return true;
}
在菜单项选择以下override
方法:
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menusettings:
//Get the intent Preference Activity
Intent i = new Intent(this, UserSettings.class);
//Start the intent and return the result
startActivityForResult(i, 1);
break;
}
return true;
}
onActivityResult
在以下代码接收结果时被调用,因此在这里执行所需的操作:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case 1:
showPreferenceSettings();
break;
}
}
从偏好设置中获取值
现在,我们想要将偏好设置屏幕中设定的值反映到主屏幕上,以展示个性化设置。
我们从偏好设置屏幕获取值,并在showPreferenceSettings()
中将其设置回主屏幕。我们通过PreferenceManager
获取偏好设置值。
private void showPreferenceSettings(){
SharedPreferences sharedPrefs =
PreferenceManager.getDefaultSharedPreferences(this);
if(sharedPrefs.getBoolean("inputUserMile", false))
cBoxMile.setChecked(true);
if(sharedPrefs.getBoolean("inputUserYard", false))
cBoxYd.setChecked(true);
if(sharedPrefs.getBoolean("inputUserFt", false))
cBoxFt.setChecked(true);
}
当点击计算按钮时,应进行转换并显示结果。为了显示结果,我们在这里使用 ToastView 命令。
当点击按钮时,会调用onClick
函数,然后我们获取单选按钮的值和选中的复选框的值,并调用相应的转换函数,然后通过以下代码通过 ToastView 显示:
public void onClick(View view ){
StringBuffer dist =new StringBuffer();
switch (view.getId()){
case R.id.calButton:
if(text.getText().length()==0){
Toast.makeText(this, "Please enter the valid number ",
Toast.LENGTH_LONG).show();
return ;
}
double distValue=Double.parseDouble
((text.getText().toString()));
//Find RadioButton is checked
if(rBtnKm.isChecked()){
//Find checkBox is checked
if(cBoxMile.isChecked()){
double km=convertKmToMile(distValue);
dist.append(km+"Mile.");
}
if(cBoxYd.isChecked()){
double yd=convertkmToYard(distValue);
dist.append(" "+yd+"yard.");
}
if(cBoxFt.isChecked()){
double ft=convertkmToFoot(distValue);
dist.append(" "+ft+"ft.");
}
Toast.makeText(this,dist,Toast.LENGTH_SHORT).show();
}
if(rBtnMtr.isChecked()){
if(cBoxMile.isChecked()){
double km=convertMToMile(distValue);
dist.append(km+"Mile.");
}
if(cBoxYd.isChecked()){
double yd=convertMtoYard(distValue);
dist.append(" "+yd+"yard.");
}
if(cBoxFt.isChecked()){
double ft=convertMtoFoot(distValue);
dist.append(" "+ft+"ft.");
}
Toast.makeText(this,dist,Toast.LENGTH_SHORT).show();
}
return;
}
}
让我们按照以下方式为每种类型添加转换方法:
private double convertKmToMile(double distance ){
return (distance*0.62137);
}
private double convertkmToYard(double distance){
return distance*1093.6;
}
为其他选项也添加其他的转换方法。
最后,在AndroidManifest.xml
文件中添加以下标签,表示一个活动。
<activity android:name=".UserSettings" />
完整的代码和资源可以在可下载的源代码中获得。
运行应用程序
当我们运行应用程序时,应该出现以下屏幕,其中第一个屏幕接受输入,点击计算按钮时输出作为 ToastView 弹出显示:
下面的截图展示了偏好设置屏幕:
本章小结
在本章中,我们了解了如何开始使用诸如复选框(CheckBox)、单选按钮(RadioButton)以及与其配合使用的菜单、创建自定义偏好设置视图并从中获取值等小部件。此外,我们使用这些概念创建了DistanceConverter
应用程序。
在下一章中,我们将学习如何处理这个应用程序的各种屏幕类型和方向。
第六章:处理多种屏幕类型
安卓设备有各种形状和大小。为了更广泛的受众,处理不同设备上的多种屏幕类型是关键。在本章中,我们将学习如何应对不同的屏幕方向变化和不同的屏幕类型。我们将使用之前讨论的DistanceConverter
应用程序,并进行更改以适应实现此目的所需的不同概念:
-
使用
wrap_content
和match_parent
适应不同屏幕 -
介绍片段(Fragment)
-
定义片段和横屏布局
-
在主布局文件中挂钩
-
运行应用程序
-
为平板电脑优化
-
在状态转换期间持久化状态信息
提示
我们将使用之前章节中的DistanceConverter
应用程序,并使用片段来定义横屏布局,以适应不同的屏幕方向和类型。
使用wrap_content
和match_parent
为了满足市场上各种安卓设备的需求,应用程序需要兼容不同的屏幕尺寸。例如,布局应适应不同的屏幕尺寸,相应的视图也应相应调整大小。为了确保我们使用wrap_content
和match_parent
来设置视图组件的宽度和高度,请参考以下内容:
-
wrap_content
:确保视图的宽度和高度设置为适应内容所需的最小尺寸 -
match_parent
:在 API 级别 8 之前,它被称为fill_parent
,确保组件扩展以匹配其父视图的大小
因此,使用这些属性确认了我们的观点,即使用所需的空间并扩展以填充可用空间。在DistanceConverter
应用程序中,我们在布局文件中的组件里使用了这些属性。下面是来自我们之前的应用程序activity_main.xml
的一个小代码片段,以演示其用法:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<RadioGroup android:id="@+id/distanceRadioGp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/distText">
</RelativeLayout>
片段
片段(Fragment)是一个独立的组件,可以连接到一个活动(Activity)或简单地视为子活动。它通常定义了一部分用户界面,但也可以不存在用户界面,即无头。片段的实例必须存在于一个活动中。
片段简化了不同布局中组件的复用。片段是实现不同类型屏幕上用户界面差异化的方式。最流行的用法是构建适用于手机的单一窗格布局和适用于平板电脑(大屏幕)的多窗格布局。片段在 Android 3.0 API 11 中引入。片段还可以用于支持纵向和横向的不同布局。
当活动停止时,片段也会停止,当活动被销毁时,片段也会被销毁。OnCreateView()
方法是创建视图 UI 的地方,通过inflate()
方法调用。以下是之前代码中我们的应用程序在横向方向上的截图:
在接下来的章节中,我们将使用片段为我们的 DistanceConverter 应用程序定义一个景观布局。
定义片段和景观布局
让我们对横向模式下的布局进行更改。为了支持横向模式的不同布局,在res
文件夹中创建一个layout-land
文件夹。在它下面创建一个activity_main.xml
文件,并添加以下代码:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="14dp"
android:layout_marginTop="44dp"
android:text="@string/distance "
android:textAppearance="?android:attr/textAppearanceMedium"/>
<EditText
android:id="@+id/distText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/textView1"
android:layout_alignBottom="@+id/textView1"
android:layout_toRightOf="@+id/textView1"
android:ems="10"
android:inputType="numberDecimal|numberSigned" />
<RadioGroup android:id="@+id/distanceRadioGp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="@+id/distText"
<RadioButton android:id="@+id/kmRadiobutton"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:checked="true"
android:text="@string/kmRadio">
</RadioButton>
<RadioButton android:id="@+id/metreRadioButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/metreRadio">
</RadioButton>
</RadioGroup>
<Button
android:id="@+id/calButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="60dp"
android:onClick="onClick"
android:text="@string/calc"
</Button>
</RelativeLayout>
在同一文件夹下创建一个fragment_checkbox.xml
文件,以定义片段的 UI。在其中添加以下代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView>
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="14dp"
android:layout_marginTop="44dp"
android:text="@string/convertTo"
android:textAppearance="?android:attr/textAppearanceMedium" />
<CheckBox
android:id="@+id/checkBoxMile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/toMile" />
<CheckBox
android:id="@+id/checkBoxYard"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/toYard" />
<CheckBox
android:id="@+id/checkBoxFoot"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/toFoot" />
</LinearLayout>
之前代码中的片段布局如下截图所示:
在放下片段的布局之后,让我们通过继承android.app.Fragment
类来定义片段。让我们创建一个名为ConvertToFragment
的片段类,并使用以下代码:
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class ConvertToFragment extends Fragment{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_checkbox,
container, false);
return view;
}
}
由于片段在 Android 3.0(也称为 API 11)中可用,我们在顶部放置了@TargetApi(Build.VERSION_CODES.HONEYCOMB)
。对于低 API 级别的设备,将没有片段,在这种情况下,我们不得不在res/layout-land
文件夹下的activity-main.xml
中定义和排列视图。
若要在低 API 级别强制使用片段,请使用支持库,这是一个 JAR 文件,允许我们使用最新的 Android API。更多信息,请参考developer.android.com/training/basics/fragments/support-lib.html
。
在onCreateView()
方法中,我们通过inflate()
方法从 XML 中填充视图。
在主布局文件中连接
打开res/layout-land
中的activity_main.xml
文件,并添加以下代码:
<fragment
android:id="@+id/convertToCheckBox"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_marginLeft="45dp"
android:layout_toRightOf="@+id/calButton"
class="com.packt.ch05.distancecon.ConvertToFragment"
tools:layout="@layout/fragment_checkbox" />
class
指向相应的片段类。tools:layout
指向相应片段的布局。
在上述步骤之后,图形布局屏幕应如下截图所示:
运行应用程序
现在我们完成了所有编程工作,让我们看看最终的应用程序会是什么样子。横向模式下的应用程序如下截图所示:
纵向模式下的应用程序如下截图所示:
提示
使用Ctrl+F11在模拟器中从纵向模式切换到横向模式,反之亦然。
针对平板电脑进行优化
平板电脑是当前环境下另一种新兴的 Android 设备。我们也应该定义布局以支持平板设备。为了适应平板设备,或者说大型设备,我们需要在res/layout-xlarge
文件夹(用于纵向模式)和layout-xlarge-land
(用于横向模式)下定义另一组布局。以下快照显示了为大型设备(平板电脑)定义布局的文件夹和文件:
一旦我们创建了相应的文件夹,就可以像之前演示的那样使用片段来创建不同的布局,并实现支持平板电脑的目标。
在状态转换期间保持状态信息
你可能已经注意到,在屏幕模式从横屏切换到竖屏,或者从竖屏切换到横屏后,复选框的状态并没有保持。这是我们应当了解的一个非常重要的概念。每次屏幕方向改变时,活动都会被销毁,然后重新创建。onCreate()
方法会被调用,因此活动的当前状态会丢失。我们需要使用onSaveInstanceSate
方法保存状态,并通过onRestoreInstanceState
方法恢复它。下面我们将重写这些方法来实现这一点:
@Override
public void onSaveInstanceState(Bundle outState)
{
//---save whatever you need to persist—
outState.putBoolean("mileChecked",cBoxMile.isChecked());
outState.putBoolean("ydChecked",cBoxYd.isChecked());
outState.putBoolean("ftchecked",cBoxFt.isChecked());
super.onSaveInstanceState(outState);
}
@Override
public void onRestoreInstanceState(Bundle savedInstanceState)
{
super.onRestoreInstanceState(savedInstanceState);
//---retrieve the information persisted earlier---
cBoxFt.setChecked(savedInstanceState.getBoolean("ftchecked"));
cBoxMile.setChecked(savedInstanceState.getBoolean("mileChecked"));
cBoxYd.setChecked(savedInstanceState.getBoolean("ydChecked"));
}
若要查看完整的源代码,请访问www.packtpub.com/support
。关于处理不同屏幕类型的更多信息,请参考以下 URL:
总结
在本章中,我们学习了片段及其使用方法,并使用它为我们的应用程序 DistanceConverter 在不同的横屏模式下实现了不同的布局。我们还学习了如何处理不同的屏幕类型,并在屏幕模式更改期间保持状态。在下一章中,我们将学习如何添加外部库,例如AdMob
,并在应用程序中嵌入广告。
第七章:添加外部库
一个 Android 应用无法独立完成所有功能,它总是需要外部 jars/库的陪伴来实现不同的目标和提供各种服务。几乎每个在商店发布的免费 Android 应用都嵌入了广告,这需要使用外部组件来实现。在 Android 应用中嵌入广告是当今应用开发的一个重要方面。在本章中,我们将继续使用前几章开发的 DistanceConverter 应用,并利用外部库AdMob
在我们的应用中嵌入广告。内容包括以下方面:
-
在
AdMob
网站创建一个账户 -
添加站点/应用
-
添加广告沉思网络
-
在应用中添加
AdMob
-
在清单文件中进行更改
-
在布局文件中添加
AdMob
小部件/视图 -
运行应用程序
在 AdMob 网站创建一个账户
AdMob
是我们在 Android 应用中嵌入广告的一种方式。要使用AdMob
,我们首先需要在www.admob.com
网站注册并获取一个账户。注册时,请访问该网站,并在右侧点击使用 AdMob 注册,然后填写表格进行注册。
下面的截图展示了注册表格:
如果我们有现有的 Google ID,可以使用它,否则前面的步骤会创建一个并将其与AdMob
账户关联。
添加站点/应用
创建账户后,我们需要添加一个站点/应用(基本上,它标识或作为广告网络放置广告的唯一句柄)。添加站点/应用需要执行以下步骤:
-
从站点与应用菜单中选择添加站点/应用,如前一个截图所示。随后会出现添加站点/应用的屏幕,如下一个截图所示:
-
选择Android 应用,如前一个截图所示,并填写其他详细信息。因为我们的应用不在市场,所以在Android 包 URL中使用http://,如前一个截图所示。
-
选择相应的类别,在本例中我们使用了工具,并在应用描述文本区域添加一些描述。同时,其他字段保持默认,输入验证码并创建站点。这之后会出现以下屏幕:
-
接下来,点击下载 AdMob Android SDK按钮下载
AdMob
SDK。下载 SDK 后,点击前往站点/应用按钮,我们的站点应该已经被添加,并会出现在站点列表中,如下一个截图所示: -
状态显示为红色,因为它还没有收到对该网站的任何广告请求。一旦开始收到对该网站的广告请求,它将自动变为绿色。
选择广告网络调解
添加网站/应用程序并下载 SDK 完成后,让我们开始添加广告网络调解(AdMob 调解)。它与其他广告网络协调,帮助我们最大化填充率(表示满足应用发送的广告请求的广告请求的百分比)并增加货币化。它确保随时选择合适的网络来投放广告。有关 AdMob 调解的更多信息,请参考以下网址:
support.google.com/admob/topic/2403413?hl=en&ref_topic=1307209
要添加广告网络调解,请按照给定的步骤操作:
-
导航到网站与应用菜单下的广告网络调解,按照以下步骤操作,如下图所示:
-
选择广告大小为横幅 - 通常 320x50,以支持大多数 iPhone 和 Android 手机在纵向模式下的显示,以及平台为Android。
有关横幅大小和决策的更多信息,请参考以下网址:
developers.google.com/mobile-ads-sdk/docs/admob/smart-banners
-
接下来,选择自动刷新,然后指定刷新率,然后点击保存并继续按钮。将会出现以下屏幕。从中选择广告网络,然后如以下截图所示点击继续:
-
从前一个截图中的选项中选择您希望的网络。
注意
我们需要在屏幕底部为所选的网络提供发布者凭据。在本例中,我们有 AdMob
的凭据,因为我们刚刚注册并且只选择了AdMob 网络,如前一个截图所示。然而,只要我们有凭据详情,我们可以自由添加任何数量的网络。此外,我们可以在任何时间点添加任何网络。
将 AdMob SDK 添加到项目中
让我们解压之前下载的 AdMob SDK zip
文件,应该会得到文件夹 GoogleAdMobAdsSdkAndroid-6.*.*
。在该文件夹下有一个 GoogleAdMobAdsSdk-6.x.x.jar
文件。将这个 JAR 文件复制到项目的 libs
文件夹中,如下截图所示:
可以以同样的方式添加其他 Java 库以在我们的项目中使用,并且为了在项目中引用 Android 库,相关信息可以在以下网址找到:
developer.android.com/tools/projects/projects-eclipse.html
在清单文件中做出更改
AdMob
需要通过互联网请求来获取广告。因此,需要在AndroidManifest.xml
文件中添加此权限,如下代码所示:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
换句话说,它还有助于 AdMob SDK 在发送请求之前确定当前可用的互联网连接。
同时,在文件中添加负责获取和显示广告的AdView
活动,如下代码所示:
<activity
android:name="com.google.ads.AdActivity"android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize" />
有关集成的更多信息,请参考以下 URL:
developers.google.com/mobile-ads-sdk/docs/
在布局文件中添加 AdMob 小部件/视图
要添加AdMob
视图,请在竖屏模式的layout/activity_main.xml
文件中添加以下代码:
<com.google.ads.AdView
android:id="@+id/adView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
ads:adSize="SMART_BANNER"
ads:testDevices="TEST_EMULATOR"
ads:adUnitId="a1516e8871e5b38"
ads:loadAdOnCreate="true"/>
同样,在横屏模式的layout-land/activity_main.xml
文件中添加同一部分代码。添加后,将显示错误,这是因为我们还没有为AdView
定义命名空间。我们接下来会做这个,错误就会消失。
在 XML 的顶部命名空间部分,与其他命名空间一起添加meta
标签:
让我们回顾一下之前使用过的AdView
的一些重要标签及其值:
项目 | 值 |
---|---|
ads:adSize |
SMART_BANNER :根据屏幕类型和方向使用屏幕宽度调整横幅大小。 |
ads:testDevices |
用于测试代码是否正常。TEST_EMULATOR 用于模拟器。如果用于测试,也可以指定设备 ID。从开发转移到生产时应移除。找到设备 ID 的最简单方法是从AdMob SDK 的日志输出中。 |
ads:adUnitId |
发布者 ID。替换为相应的 ID。 |
ads:loadAdOnCreate |
通过膨胀创建视图,并向AdMob 发送广告请求。 |
在前一个案例中,我们是通过 XML 加载Adview
并发出请求。还有一种方法,通过在MainActivity.java
文件的onCreate()
方法中放置以下代码来实现,如下代码片段所示:
adView = (AdView)findViewById(R.id.adView);
AdRequest re = new AdRequest();
re.setTesting(true);
adView.loadAd(re)
提示
在 Android 应用准备发布到商店之前,确保移除测试模式。
运行应用程序
经过所有辛勤的工作后,让我们运行应用程序来看看它的样子。在横屏模式下,广告将如下截图所示出现:
在竖屏模式下,广告将如下截图所示出现:
第一次AdMob
广告可能需要 1 到 2 分钟才能显示,所以请耐心等待。
总结
在本章中,我们学习了如何通过在 DistanceConverter 应用程序中整合AdMob
移动广告,来添加外部库。
在下一章中,我们将学习签署并准备发布应用程序需要什么。
第八章:签名和分发 APK
所有至今为止的辛勤工作,除非我们分发应用供他人使用,否则都是徒劳的。安卓应用在上架分发前必须进行签名。任何安卓应用,无论是用于模拟器,还是分发给朋友、亲戚测试,或者发布到 Google Play 商店,都需要进行电子签名。在本章中,我们将学习如何签名并发布供他人使用。本章将涵盖以下内容:
-
APK (Android 包)
-
准备发布
-
发布编译
-
生成私钥
-
使用 Eclipse ADT 进行发布
-
发布到 Google Play
APK – 安卓包
安卓包(APK)简单来说,类似于可运行的 JAR 或可执行文件(在 Windows 操作系统上),它包含了运行应用所需的一切。
安卓生态系统使用虚拟机,即Dalvik 虚拟机(DVM)来运行 Java 应用。Dalvik 使用自己的字节码,这与 Java 字节码有很大不同。
Android SDK 下的工具dx
将我们的 Java 类转换为.dex
(Dalvik 可执行文件)。
工具aapt(安卓资源打包工具)将.dex
文件和应用资源(XML 和图片)打包到.apk
文件中。
准备发布
经过编码和测试的辛勤工作后,应用需要被打包以便发布。打包包括以下步骤。
发布编译
这是发布和分发的第一步。它包括在应用的清单文件中设置包名,配置应用属性,以及发布前的编译。它们包括以下步骤:
-
选择合适的包名:一旦应用发布,就无法撤回,因此需要仔细考虑并选择一个合适的包名。包名可以在应用的清单文件中设置。
-
禁用调试:我们需要确保在发布之前禁用调试。要禁用调试,可以在代码中注释或移除
Log()
方法调用。此外,通过从<application>
标签中移除android:debuggable
属性也可以禁用调试。 -
指出应用图标:每个应用都需要有自己的图标。请确保图标遵循图标指南:
developer.android.com/guide/practices/ui_guidelines/icon_design_launcher.html
。图标可以通过使用<application>
标签的 icon 属性来指定。
版本控制:这是发布和维护最重要的方面。版本标识应用程序的发布版本,并确定其更新方式。简单来说,每次发布时版本号必须递增。如果没有版本号,未来更新几乎是不可能的。版本信息由以下两个属性提供:
android:versionCode |
这是一个表示应用程序版本的整数。 |
---|---|
android:versionName |
这是显示给用户以识别设备中安装内容的字符串。 |
这两个属性都可以在 <manifest>
元素下指定。
- 检查权限清单文件:它应该只使用
<uses-permission>
标签在清单文件中指定相关权限。
生成私钥
安卓应用程序必须使用我们自己的私钥进行签名。它标识与该应用程序相关联的人、公司或实体。这可以通过使用 Java SDK 中的程序 keytool
来生成。以下命令用于生成密钥:
keytool -genkey -v -keystore <filename>.keystore -alias <key-name> -keyalg RSA -keysize 2048 -validity 10000
我们可以为每个发布的应用程序使用不同的密钥,并为它指定一个不同的名称以进行标识。另外,谷歌期望有效期至少为 25 年或更长时间。一个非常重要的考虑是要备份并安全地存储密钥,因为一旦密钥泄露,就不可能更新已经发布的应用程序。
签名
获取私钥后,我们需要对应用程序进行签名。这是使用 Java SDK 中的程序 jarsigner
完成的。使用以下命令:
jarsigner -verbose -sigalg MD5withRSA -digestalg SHA1 -keystore my-release-key.keystore
my_application.apk alias_name
对齐
一旦 APK 文件被签名,就需要对其进行优化。为此,我们使用 Android SDK 中的 tools/
目录下的 zipalign
工具。使用方法如下:
zipalign -v 4 your_project_name-unaligned.apk your_project_name.apk
使用 Eclipse ADT 发布
使用 Eclipse Android 开发工具 (ADT),准备发布 部分中提到的所有步骤都可以轻松完成。让我们使用 Eclipse ADT 为前一章中的 DistanceConverter 准备发布。
按照以下步骤操作:
-
右键点击项目 DistanceConverter,然后从上下文菜单中选择 Export。选择 Export Android Application,如下所示截图:
-
Export 向导现在将指导您完成签名过程,包括选择私钥的步骤(如果已经使用工具生成),或者创建新的密钥库和私钥。以下是一些截图,第一张是创建密钥库的截图。
-
现在选择 Create new keystore 并提供 Location 和 Password 的值:
-
在以下屏幕中,我们可以根据下表输入有关密钥创建的其他详细信息:
-
在导出 Android 应用向导中,填写相应的详细信息:
字段 值 别名 DIS
– 这是密钥别名名称密码 <密码>
有效期 25
– 对于在 Google Play 上发布,截至 2033 年 10 月 22 日的期限是必须的名字和姓氏 <姓名>
组织单位 个人 组织 个人 市/地区 <城市名称>
州/省 <州名称>
国家代码(xx) 两个字母代码(例如,US) -
点击完成,结果就会被编译、签名、对齐,并准备好分发。
发布到 Google Play
在 Google Play 上发布非常简单,包括以下步骤:
-
注册 Google Play: 访问并注册
play.google.com/
。注册需要 25 美元,过程相当直接,可能需要几天时间才能获得最终访问权限。 -
上传 APK: 注册完成后,用户需要登录并使用上传应用链接上传 APK 文件。此外,他们还需要上传所需的资源,并编辑列表详情,这些是用户在商店浏览应用时将看到的内容。
-
使用发布按钮来完成这项任务。
获取帮助
有关签名和发布的更多信息和支持,请参考以下链接:
摘要
在本章中,我们了解了签名和分发 APK 涉及的步骤,以及如何通过 Eclipse ADT 轻松实现这一过程。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!