一、Android Studio 简介
本章将引导您安装和设置您的开发环境,以便您可以遵循本书中的示例和实验。首先,您将安装一个名为 Java 开发工具包(JDK)的必备组件。然后,您将下载并安装 Android Studio 以及 Android 软件开发工具包(SDK),这是构建 Android 应用所需的一套软件工具。我们将向您展示如何使用 New Project 向导来创建一个名为 HelloWorld 的简单项目。最后,我们将向您展示如何建立到 Android 虚拟设备(AVD)和物理 Android 设备的连接。本章结束时,你将拥有在 Android Studio 中开始开发应用所需的一切。
在 Windows 上安装 Java 开发工具包
本节适用于 Windows 用户。如果您是 Mac 用户,请跳到“在 Mac 上安装 Java 开发工具包”一节 Android Studio 使用 Java 工具链进行构建,因此在开始使用 Android Studio 之前,您需要确保您的计算机上安装了 Java 开发工具包(JDK)。很有可能你的电脑上已经安装了 JDK,尤其是如果你是一个经验丰富的 Android 或 Java 开发人员。如果您的计算机上已经安装了 JDK,并且运行的是 1.6 版或更高版本,那么您可以跳过这一部分。但是,您可能还是想下载、安装和配置最新的 JDK。您可以从以下 Oracle 站点下载 JDK:
www.oracle.com/technetwork/java/javase/downloads/index.html
当你登陆这个页面时,点击 Java 下载按钮,如图 1-1 所示。
图 1-1。
The Java Download button on the Java Downloads page
在 Windows 上下载 JDK
如图 1-2 所示,安装的下一步要求您通过单击 Accept License Agreement 单选按钮接受许可协议。然后,您必须为您的操作系统选择合适的 JDK。如果你运行的是 Windows 7 或 Windows 8,你应该点击 Windows x64 标签右边的文件链接,也如图 1-2 所示。Oracle 经常对 JDK 进行版本更新。到本书付印时,几乎可以肯定的是,JDK 的新版本将会推出,所以请务必下载最新版本。等待安装文件下载。这个文件通常在 125MB 左右,所以下载不会花很长时间。
图 1-2。
Accept the license agreement and click the appropriate link for Windows
在 Windows 上执行 JDK 向导
在安装 JDK 之前,在您的C:
驱动器的根目录下创建一个名为Java
的目录。这个目录的名字是任意的,尽管我们称它为Java
,因为我们要在这里安装的许多工具都与 Java 相关,包括 JDK、Android Studio 和 Android SDK。将与 Android Studio 相关的工具一致地安装在C:\Java
目录中也可以让您的开发环境保持有序。
导航到浏览器下载安装文件的位置,双击该文件执行安装。安装开始后,会出现安装向导,如图 1-3 所示。在 Windows 中,JDK 安装程序默认为C:\Program Files\Java\
。要更改安装目录位置,请单击“更改”按钮。我们建议将您的 JDK 安装在C:\Java
目录中,因为它的路径名中不包含空格,而且容易记忆。见图 1-4 。
图 1-4。
Select the JDK installation directory
图 1-3。
Installation Wizard for the JDK on Windows
记下您安装 JDK 的位置。按照提示操作,直到安装完成。如果提示安装 Java Runtime Edition (JRE ),请选择安装 JDK 的目录。
在 Windows 上配置环境变量
本节将向您展示如何配置 Windows,以便 Android Studio 可以找到 JDK。在运行 Windows 的计算机上,按住 Windows 键并按下 Pause 键打开系统窗口。点击高级系统设置选项,如图 1-5 所示。
图 1-5。
Windows System window
点击环境变量按钮,如图 1-6 所示。在底部的系统变量列表中,如图 1-7 所示,导航到JAVA_HOME
项。如果JAVA_HOME
项不存在,单击新建创建它。否则,单击编辑。
图 1-7。
Environmental variables
图 1-6。
System properties
点击新建或编辑显示类似图 1-8 的对话框。确保在变量名字段中输入JAVA_HOME
。在变量值字段中,输入之前安装 JDK 的位置(去掉任何尾随斜线),如图 1-4 所示。现在点击确定。
图 1-8。
Edit the JAVA_HOME environmental variable
正如您对JAVA_HOME
环境变量所做的一样,您将需要编辑PATH
环境变量。见图 1-9 。将光标放在变量值字段的末尾,并键入以下内容:
图 1-9。
Edit the PATH environmental variable
;%JAVA_HOME%\bin
现在,单击确定、确定、确定接受这些更改并退出系统属性。
要测试新的 JDK 是否已正确安装,请单击开始按钮,键入 cmd,然后按 Enter 键。
在命令行窗口中,发出以下命令并按 Enter 键:
java –version
如果您得到如图 1-10 所示的响应,那么恭喜您。您刚刚正确安装了 JDK。
图 1-10。
Confirm the proper JDK installation
在 Mac 上安装 Java 开发工具包
安装 Mac 版和 Windows 版 JDK 的前两步是相同的。将您的浏览器指向以下站点:
www.oracle.com/technetwork/java/javase/downloads/index.html
当你登陆这个页面时,点击 Java 下载按钮,如图 1-11 所示。
图 1-11。
The Java Download button on the Java Downloads page
在 Mac 上下载 JDK
点击接受许可协议单选按钮,接受许可协议,如图 1-12 所示。然后,您必须为您的操作系统选择合适的 JDK。如果你运行的是 64 位版本的 OS X,你应该点击 Mac OS X64 标签右边的文件链接,也如图 1-12 所示。Oracle 经常对 JDK 进行版本更新。到本书付印时,几乎可以肯定的是,JDK 的新版本将会推出,所以请务必下载最新版本。等待安装文件下载。
图 1-12。
Accept the license agreement and click the appropriate link for Mac
在 Mac 上执行 JDK 向导
双击.dmg
文件执行它。现在点击.pkg
文件开始向导,根据需要点击继续,如图 1-13 到 1-15 所示。
图 1-15。
Installation success
图 1-14。
Installation Wizard
图 1-13。
JDK 8 Update 25.pkg
在 Mac 上配置 JDK 版本
要配置 Mac 以便 Android Studio 可以找到正确的 JDK,请打开 Finder 窗口并选取“应用”“➤实用工具”。在那里,打开 Java Preferences,并按照指示将新版本拖到列表的顶部,以便它被识别为首选版本。
安装 Android Studio
在开始下载 Android Studio 之前,为您将在本书中创建的 Lab 创建一个 Lab 父目录。我们在整本书中使用C:\androidBook\
作为我们 Lab 的父目录,但是你可以选择或创建任何你认为合适的目录。因此,我们简单地称它为 labs 父目录。
下载 Android Studio 很简单。将您的浏览器指向此站点:
developer.android.com/sdk/installing/studio.html
现在点击绿色的下载 Android Studio for your OS 按钮,如图 1-16 所示。接下来,选中标记为“我已阅读并同意上述条款和条件”的复选框。再次单击 Download Android Studio for your OS,您的安装文件应该开始下载。下载完成后,执行刚刚下载的文件。
图 1-16。
Download Android Studio
安装向导开始后,通过单击“下一步”按钮浏览其屏幕,直到到达“选择组件”屏幕。在那里,选中所有组件复选框,如图 1-17 所示。然后单击下一步。再次同意条款和条件。当你进入配置设置:安装位置屏幕,如图 1-18 所示,选择 Android Studio 和 Android SDK 的位置。为了保持一致,我们选择在C:\Java\astudio\
安装 Android Studio,在C:\Java\asdk\
安装 Android SDK。
图 1-18。
Select locations for Android Studio and the SDK
图 1-17。
Choose components
安装 Android Studio 和 Android SDK 时,点击几个后续按钮。你应该最终到达完成 Android Studio 设置屏幕,如图 1-19 所示。“启动 Android Studio”复选框使 Android Studio 能够在您单击“完成”后启动。确保复选框被选中,然后点击 Finish,Android Studio 将启动。请注意,从现在开始,您需要导航到桌面图标或开始菜单来启动 Android Studio。
图 1-19。
Completing the Android Studio setup
当 Android Studio 第一次启动时,如图 1-20 所示,设置向导将分析您的系统,寻找现有的 JDK(如您之前安装的那个),以及 Android SDK 的位置。设置向导应该下载你在 Android Studio 中开始开发应用所需的一切。单击“完成”按钮退出安装向导。
图 1-20。
Setup Wizard – Downloading Components
创建您的第一个项目:HelloWorld
一旦设置向导完成,欢迎使用 Android Studio 对话框出现,如图 1-21 所示。单击开始新的 Android 项目选项。
图 1-21。
Welcome to Android Studio
在出现的新建项目向导中(见图 1-22 ,在应用名称字段中键入 HelloWorld,在公司域字段中键入 gerber.apress.com。请注意,包名是反向公司域加上项目名。将 HelloWorld 项目安装在 labs 父目录的根目录下。如前所述,如果你运行 Windows,我们使用C:\androidBook\
。如果您运行的是 Mac 或 Linux,您的 Lab 父目录名称不会以字母开头,而是以正斜杠开头。
图 1-22。
Configure your new project
Android 操作系统可以在许多平台上运行,包括游戏机、电视、手表、眼镜、智能手机和平板电脑。默认情况下,手机和平板电脑复选框将被选中,API-8 将被选为最低 SDK。接受这些设置,点击下一步,如图 1-23 所示。
图 1-23。
Select the form factors your app will run on
新建项目向导中的后续屏幕提示您选择布局。选择空白活动,然后单击下一步按钮。接受默认名称,如图 1-24 所示。它们应该如下:
- 活动名称:主活动
- 布局名称:活动 _ 主要
- 标题:MainActivity
- 菜单资源名称:menu_main
图 1-24。
Choose options for your new file
使用 Android 虚拟设备管理器
Android 虚拟设备管理器允许您创建 Android 虚拟设备(avd),然后您可以运行它来模拟您计算机上的设备。模拟和仿真之间有一个重要但微妙的区别。模拟意味着虚拟设备只是模拟实际物理设备行为的一个门面,但并不运行目标操作系统。iOS 开发环境使用模拟,考虑到该平台可用的设备数量有限,这可能是 iOS 的一个好选择。
但是,使用仿真时,您的计算机会留出一块内存来再现仿真器正在仿真的设备上的环境。Android Studio 使用模拟,这意味着 Android 虚拟设备管理器启动 Linux 内核和整个 Android 堆栈的沙盒版本,以便模拟物理 Android 设备上的环境。尽管仿真提供了一个比模拟更可靠的环境来测试你的应用,但是启动 AVD 可能需要几分钟,这取决于你的电脑速度。好消息是,当您的模拟器在内存中激活后,它仍然可以响应。然而,如果你有安卓手机或平板电脑,我们建议使用物理设备来测试你的应用,而不是使用 AVD。也就是说,让我们首先使用 Android 虚拟设备管理器设置一个 AVD,在本章的后面,我们将向您展示如何连接您的物理设备,如果您有物理设备的话。
点击图 1-25 中圈出的 Android 虚拟设备管理器图标。在 Andriod 虚拟设备管理器向导的第一个屏幕上,单击创建虚拟设备按钮。在下一个屏幕上,如图 1-26 所示,选择 Galaxy Nexus 并点击下一步。下一个屏幕如图 1-27 所示,允许您选择系统图像。为 ABI 为 x86_64 的 Lollipop(或最新的 API)选择第一个选项。单击下一步。在下一个屏幕上,单击完成按钮验证您的 AVD 设置。恭喜你,你刚刚创建了一个新的 AVD。
图 1-27。
Select the x86_64 system image
图 1-26。
Select the Galaxy Nexus hardware
图 1-25。
AVD icon Note
x86_64 版本需要英特尔硬件加速,它只能在有限数量的英特尔芯片组上运行。如果您尝试安装 x86_64 并且失败,请尝试 armeabi-vxx 版本。
Tip
如果您想要为 Android Studio 还没有设备定义的设备创建 AVD,我们建议您前往 phonearena.com
并搜索您的型号。在那里你可以找到技术规范,你可以用它来创建一个新的设备定义。创建新的设备定义后,使用相同的步骤创建新的 AVD。
市面上有一款优秀的第三方 Android 模拟器,叫做 Genymotion。Genymotion 模拟器是免费的,用于非商业目的,性能非常好。解释如何设置和使用 Genymotion 超出了本书的范围,但是你可以从 genymotion.com
下载 Genymotion 模拟器。
在 AVD 上运行 HelloWorld
要在新创建的 AVD 上运行你的 HelloWorld 应用,点击工具栏上绿色的 run 按钮,如图 1-28 所示。
图 1-28。
Run button
确保选择了 Launch Emulator 单选按钮,然后在组合框中选择 Galaxy Nexus API 21。点击确定,如图 1-29 所示。请耐心等待,因为启动 AVD 可能需要几分钟时间。你现在应该看到你的 HelloWorld 应用在你电脑的一个窗口中运行,如图 1-30 所示。
图 1-30。
Emulator screenshot
图 1-29。
Choosing a device and launching the emulator
在 Android 设备上运行 HelloWorld
如前所述,虽然 avd 对于模拟特定设备很有用,尤其是那些你手头没有的设备,但在物理 Android 设备上开发应用更受欢迎。如果当您通过 USB 电缆将 Android 设备连接到您的电脑时,您的电脑无法识别您的 Android 设备,您可能需要 USB 驱动程序。如果您的计算机最初识别您的 Android 设备,您可能应该放弃安装不同或更新版本的 USB 驱动程序,因为这可能会导致 USB 连接失败。
Note
Mac 和 Linux 用户通常不需要下载 USB 驱动程序来在其 Android 设备和计算机之间建立 USB 连接。
您可以使用developer.android.com/tools/extras/oem-usb.html#Drivers
处的表格来查找合适的 USB 驱动程序,或者使用您喜欢的搜索引擎来查找适用于您的型号的 USB 驱动程序。下载驱动程序并安装在您的计算机上。在 Android 设备上,点击设置,然后点击开发者选项。确保选中了 USB 调试复选框。有些设备(如 Samsung 设备)需要密码才能启用 USB 调试,因此您可能希望使用您最喜欢的搜索引擎来研究如何在您的设备上启用 USB 调试。如果这个过程不是很明显的话,YouTube 也是一个很好的视频来源,可以教你如何在你的特定设备上启用 USB 调试。
大多数 Android 设备都配有一根电缆,一端有一个 USB 插头,另一端有一个微型 USB 插头。使用此电缆将您的 Android 设备连接到电脑。点击图 1-31 中圈出的 Android 设备监控按钮。如果驱动程序安装正确,你应该看到设备在那里列出并连接,如图 1-32 所示。
图 1-32。
Android Device Monitor screen showing the connected physical device
图 1-31。
Android Device Monitor button Note
请记住,您的计算机和 Android 设备之间的连接是通过使用一个名为 Android Debug Bridge (ADB)的服务器建立的。如果看不到该设备,请单击 IDE 左下角的终端按钮,并发出以下命令:
adb start-server
如果重新启动 ADB 服务器后,您仍然看不到该设备,虽然可能性不大,但 USB 驱动程序需要重新启动系统才能生效。
现在点击绿色的运行按钮(如之前图 1-28 所示)。选择连接的 Android 设备。在图 1-33 中,连接的设备是 HTC One X Android 智能手机。点击 OK,等待几秒钟,你会看到 HelloWorld 在你的 Android 设备上运行。
图 1-33。
The Choose Device screen with the physical Android device listed
摘要
在这一章中,你安装了 Java 开发工具包,或 JDK,你也安装了 Android Studio 和 Android SDK。您使用新建项目向导创建了一个名为 HelloWorld 的简单应用。然后你创建了一个 Android 虚拟设备,或 AVD。我们向您展示了如何安装任何所需的 USB 驱动程序。最后,我们向您展示了如何在 AVD 和物理 Android 设备上启动 HelloWorld。现在,您应该已经拥有了在 Android Studio 中开发 Android 应用所需的所有软件。
二、导航 Android Studio
Android Studio 是一个窗口环境。为了最大限度地利用有限的屏幕空间,并防止你不知所措,Android Studio 在任何时候都只显示一小部分可用窗口。其中一些窗口是上下文相关的,只有在上下文合适时才会出现,而其他窗口则保持隐藏,直到您决定显示它们,或者相反,保持可见,直到您决定隐藏它们。为了充分利用 Android Studio,您需要了解这些窗口的功能,以及如何和何时显示它们。在这一章中,我们将向你展示如何在 Android Studio 中管理窗口。
任何集成开发环境(IDE)的基本功能之一就是导航。Android 项目通常由许多包、目录和文件组成,一个中等复杂程度的 Android 项目可能包含数百个这样的素材。您使用 Android Studio 的效率将在很大程度上取决于您在这些素材中导航的舒适程度。在本章中,我们还将向您展示如何在 Android Studio 中导航。
最后,我们将向您展示如何使用 Android Studio 中的帮助系统。为了充分利用本章,打开我们在第一章中创建的 HelloWorld 项目。如果这个项目已经在 Android Studio 中打开,您就可以开始了。当我们讨论以下导航功能时,请参考图 2-1 。
图 2-1。
Android Studio’s integrated development environment
编辑
任何 IDE 的主要目的都是编辑文件。正如所料,允许用户在 Android Studio 中编辑文件的窗口位于 IDE 的中央窗格。编辑器窗口在窗口中是唯一的,因为它总是可见的,并且总是位于中心窗格。事实上,编辑器窗口是 Android Studio 的一个非常普遍的特性,从现在开始,我们将它简称为编辑器。Android Studio 中的所有其他窗口被称为工具窗口,聚集在编辑器周围的侧窗格(左侧、底部和右侧)中。
编辑器是一个选项卡式窗口,在这方面,它类似于当代的 web 浏览器。当您从其中一个工具窗口、键盘快捷方式或上下文菜单中打开文件时,该文件将显示为编辑器的一个选项卡。正如您在构建第一个项目 HelloWorld 时已经发现的那样,MainActivity.java
和activity_main.xml
文件会作为标签自动加载到编辑器中。Android Studio 试图预测您可能会开始编辑哪些文件,然后在完成新建项目向导后,自动在编辑器中以标签形式打开它们。几乎任何文件都可以在编辑器中打开,尽管原始图像和声音文件还不能在 Android Studio 中编辑。您也可以将文件从工具窗口拖放到编辑器上;这样做可以在编辑器中将文件作为选项卡打开。
编辑器顶部是编辑器标签。沿着编辑器的左边界是装订线,沿着编辑器的右边界是标记栏。让我们依次检查每一个。
编辑器选项卡
要在 Android Studio 的编辑器选项卡中导航,请使用 Alt+右箭头键| Ctrl+右箭头键或 Alt+左箭头键| Ctrl+左箭头键。当然,你可以用鼠标选择一个编辑器标签。编辑器选项卡的选项位于➤编辑器选项卡窗口的主菜单栏中。从该菜单中选择的任何操作都适用于当前选定的选项卡。将鼠标滚动到MainActivity.java
选项卡上,右键单击(在 Mac 上按住 Ctrl 键单击)它。在产生的上下文菜单中,如图 2-2 所示,您会注意到许多与您在窗口➤编辑器选项卡中发现的选项相同的选项。从该上下文菜单中,选择选项卡放置子菜单。菜单选项“上”、“下”、“左”和“右”允许您移动标签栏。向右或向左移动标签栏可以容纳更多可见的标签,尽管这是以牺牲屏幕空间为代价的。
图 2-2。
Editor tab context menu
编辑器选项卡上下文菜单的关闭和关闭所有操作非常简单。当您想要关闭除活动标签之外的所有标签时,可以使用“关闭其他标签”操作。“垂直拆分”和“水平拆分”操作用于将编辑器细分为多个窗格。如果您想并排比较两个文件,垂直拆分特别有用。您可以无限分割窗格,尽管这种嵌套分割的效用会很快减少。您还可以将文件从其他窗口拖放到编辑器的任何窗格,或者从一个窗格拖放到另一个窗格。关闭窗格的最后一个选项卡会导致整个窗格消失。
阴沟
装订线用于传达关于代码的信息。也许 gutter 最明显的特征是小色板和图像图标显示在引用这些视觉资源的相应代码行旁边。装订线还用于设置断点、方便代码折叠和显示范围指示器。所有这些特性将在随后的章节中详细介绍。
标记栏
编辑器右侧是标记栏。标记栏用于指示源文件中重要行的位置。例如,标记栏突出显示 Java 或 XML 文件中的警告和编译时错误。标记栏还显示未提交的更改、搜索结果和书签的位置。
标记栏不会像装订线那样滚动;相反,标记栏上的彩色记号是相对于文件的长度定位的。单击标记栏中的彩色勾号会立即跳转到文件中的该位置。现在,通过单击标记栏上的一些彩色标记来练习使用标记栏。
工具按钮
您已经看到了默认情况下显示在左侧窗格中的项目工具窗口。要查看所有工具窗口的列表,请从主菜单栏中选择查看➤工具窗口。现在仔细观察 IDE 的左、右和下边缘。在那里,您可以找到与许多工具窗口相对应的工具按钮。请注意,其中一些工具按钮还标有数字,该数字与 Alt(Mac 上的 Cmd)键结合使用,以打开/关闭该工具按钮对应的工具窗口。现在尝试单击工具按钮来练习这项技能。还要练习使用快捷键 Alt+1 | Cmd+1、Alt+2 | Cmd+2、Alt+3 | Cmd+3 等等来切换工具窗口的打开/关闭。
当工具窗口打开时,相应的工具按钮是暗灰色的,表示它被按下。请注意,工具按钮位于页边距的角上。例如,“项目”工具按钮的默认位置在左边距的右上角,而“个人收藏”工具按钮默认位于左边距的左下角。
侧窗格(左侧、底部和右侧)一次最多可以由两个工具窗口共享。要查看如何共享侧窗格,请同时打开收藏夹和项目工具窗口。请注意,“个人收藏”和“项目”工具按钮位于同一页边空白的对角。如果两个工具窗口的对应工具按钮位于同一角落,则尝试在这两个工具窗口之间共享侧窗格将不起作用。例如,项目和结构工具窗口不能同时显示——至少在 Android Studio 的默认配置中不能。
默认布局
不要混淆 Android Studio 中的默认布局和 Android SDK 中的布局。默认布局是聚集在编辑器周围的一组特定的工具窗口。Android Studio 配置为开箱即用,默认布局在左侧窗格中显示项目工具窗口。这是之前在图 2-1 中显示的布局。
让我们来看看主菜单栏中的窗口菜单。前两个菜单项是将当前布局存储为默认布局和恢复默认布局。“恢复默认布局”操作通常在 IDE 变得过于拥挤时使用,或者您只想清除白板并返回到熟悉的布局。您也可以自定义默认布局,方法是打开和关闭您喜欢的任何工具窗口,调整它们的大小和/或位置,然后通过选择“将当前布局存储为默认值”将该新布局设置为默认布局。
Repositioning Tool Buttons
如上所述,项目和结构工具窗口不能同时显示,因为它们对应的工具按钮位于同一角落。但是,您可以将任何工具按钮移动到您想要的任何角落。将“结构”工具按钮拖放到左边距的左下角。现在,通过使用键盘快捷键 Alt+1 | Cmd+1 和 Alt+7 | Cmd+7 或通过单击它们的工具按钮来切换项目和结构工具窗口打开。因为我们将它们的工具按钮移动到对角,所以项目和结构工具窗口现在可以共享同一个侧窗格并同时显示。
导航工具窗口
本节讨论专门用于导航的工具窗口:项目、结构、收藏夹、待办事项和命令。表 2-1 列出了每个导航工具窗口的功能。后续章节涵盖了许多其他工具窗口。
表 2-1。
Navigation Tool Windows
| 工具窗口 | 电脑钥匙 | Mac 密钥 | 功能 | | --- | --- | --- | --- | | 项目 | Alt+1 | Cmd+1 | 允许您在项目中导航文件和资源 | | 收藏夹 | Alt+2 | Cmd+2 | 显示收藏夹、书签和断点 | | 结构 | Alt+7 | Cmd+7 | 显示当前文件中对象或元素的分层树 | | 指挥官 | | | 类似于项目工具窗口,但允许轻松管理文件 | | 待办事项 | | | 显示项目中所有活动待办事项的列表 |项目工具窗口
我们发现项目工具窗口是最有用的导航工具窗口,因为它结合了广泛的范围和相对容易的访问。要了解项目工具窗口的功能和范围,您可能需要将窗口的模式设定为项目。有三种模式;项目、包和 Android。默认情况下,Android Studio 会将模式设置为 Android。Android 和 Project 是最有用的模式,尽管 Android 模式可能会对你隐藏某些目录。模式设置组合框位于 90 度角,靠近 IDE 左上角的项目工具按钮。项目工具窗口提供了一个简单的树状界面,其中包含可以切换的文件和嵌套目录。“项目工具”窗口提供了项目中所有包、目录和文件的概述。如果在“项目工具”窗口中右键单击(在 Mac 上按住 Ctrl 键单击)某个文件,将会出现一个上下文菜单。此上下文菜单中有三个重要的菜单项:复制路径、文件路径和在资源管理器中显示。单击复制路径将操作系统到该文件的绝对路径复制到剪贴板。单击文件路径会将路径显示为一堆目录,文件位于顶部,单击这些目录中的任何一个都会在操作系统中打开它们。单击“在资源管理器中显示”会在操作系统的新窗口中显示该文件。参见图 2-3 。
图 2-3。
The Project tool window
结构工具窗口
“结构工具”窗口显示文件中元素的层次结构。当编辑器显示一个 Java 源文件如MainActivity.java
时,结构工具窗口显示一个元素树,如字段、方法和内部类。当编辑器显示一个 XML 文件(如activity_main.xml
)时,结构工具窗口会显示一个 XML 元素树。单击结构工具窗口中的任何元素都会立即将光标移动到编辑器中的该元素。结构工具窗口对于在大型源文件中的元素间导航特别有用。通过打开结构工具窗口并在MainActivity.java
和activity_main.xml
的元素间导航来练习这项技能。见图 2-4 。
图 2-4。
The Structure tool window
收藏夹工具窗口
在 Android 中开发一个特性(或调试一个 bug)时,您可能会创建或修改几个相关的文件。中等复杂程度的 Android 项目可能包含数百个单独的文件,因此将相关文件分组的能力确实很有用。“收藏夹”工具窗口包含收藏夹,这些收藏夹允许您对相关文件的引用进行逻辑分组,否则这些文件可能位于项目中完全不同的部分。
确保MainActivity.java
和activity_main.xml
文件都作为标签加载到编辑器中。现在右键单击(在 Mac 上按住 Ctrl 键)编辑器中的任一选项卡,并从上下文菜单中选择“全部添加到收藏夹”。在输入新的收藏夹列表名称字段中,键入 main,然后按确定。如果收藏夹工具窗口未打开,请通过切换 Alt+2 | Cmd+2 来激活它。展开名为 main 的收藏夹项目,双击其中列出的一个文件将其打开/激活。
就像“收藏夹”窗口允许您立即导航到任何特定的文件或文件组一样,书签允许您立即导航到文件中的任何特定行。将光标定位在MainActivity.java
中的任意一行。现在按 F11(在 Mac 上按 F3)。这项动作会在任何来源档案(包括 XML 档案)中建立或移除书签。请注意槽中的勾号和标记栏中指示新书签的黑色勾号。要查看刚刚创建的书签,请在收藏夹工具窗口中切换打开书签。
Note
在 PC 上,如果 F11 似乎没有响应,请检查以确保键盘上的 F-Lock 键已被激活。
断点用于调试。与可以在任何文件中设置的书签不同,您需要在 Java 源文件中设置断点。打开MainActivity.java
并点击下一行代码旁边的空白处:
setContentView(R.layout.activity_main);
您会注意到一个红色的圆圈现在占据了檐槽,并且这条线也被突出显示为红色。只能在可执行代码行上设置断点;例如,试图在注释行上设置断点是行不通的。若要查看新创建的断点,请在收藏夹工具窗口中切换打开断点树。你可以用断点做几件更有趣的事情,我们在专门讨论调试的第十二章中详细讨论了断点。
待办事项工具窗口
TODO 的意思当然是做。TODOs 本质上是向程序员和他们的合作者表明还有工作要做的注释。TODO 的写法类似于注释,以两个正斜杠、全大写的 TODO 和一个空格开始。例如:
//TODO inflate the layout here.
在MainActivity.java
中创建一个待办事项,打开待办事项工具窗口查看。单击 TODO 工具窗口中的 TODO 会立即跳转到源代码中的该 TODO。
管理器工具窗口
“管理器工具”窗口是一个导航辅助工具,有左右两个窗格。这些窗格的功能与项目和结构工具窗口非常相似。Commander 工具窗口与其他导航窗口的不同之处在于,它一次只显示一个目录级别,而不是显示嵌套的目录树。如果您更喜欢 Windows 风格的导航,或者您发现项目工具窗口太大,那么 Commander 工具窗口可能是一个不错的导航选择。
主菜单栏
主菜单栏是 Android Studio 中最上面的栏,你可以通过浏览它的菜单和子菜单来执行几乎任何操作。与 Android Studio 中的其他栏不同,主菜单栏无法隐藏。不要被主菜单栏及其子菜单中包含的众多操作所淹没。即使是最有经验的 Android 开发人员每天也只会使用这些操作中的一小部分,而且大多数操作都有相应的键盘快捷键和/或上下文菜单项。我们将在后续章节中讨论主菜单栏中包含的许多操作。
工具栏
工具栏包含常用文本操作的按钮,如剪切、复制、粘贴、撤消和重做。正如你已经在第一章中看到的,工具栏还包含了 Android Studio 中各种管理器的按钮,包括 SDK 管理器和 Android 虚拟设备管理器。工具栏还有用于设置和帮助的按钮,以及用于运行和调试应用的按钮。工具栏中的所有按钮都有相应的菜单项和键盘快捷键。高级用户可能希望通过取消选中“查看➤工具栏”菜单项来隐藏工具栏,以节省屏幕空间。
导航栏
导航栏显示一系列水平箭头框,代表从项目根目录(左侧)到编辑器中当前选定选项卡(右侧)的路径。导航栏可用于导航项目资源,而无需求助于项目或管理器工具窗口。
状态栏
状态栏如图 2-5 (之前在图 2-1 中)所示,显示相关的和上下文敏感的反馈,例如关于任何运行的进程或者你的项目的 Git 库的状态的信息。现在让我们更详细地研究一下状态栏。
图 2-5。
Status bar
状态栏的最左边是“切换边距”按钮。单击此按钮可切换隐藏和显示页边距。此外,当您将鼠标悬停在此按钮上时,会出现一个上下文菜单,允许您激活任何工具窗口。
消息区域用于提供反馈并显示有关并发运行进程的任何信息。当您将鼠标滚动到 UI 元素(如工具栏中的菜单项或按钮)上时,该区域也会显示提示。单击此区域将打开事件日志。
编辑器光标位置以行:列格式显示光标在编辑器中的位置。单击此区域会激活一个对话框,允许您直接导航到代码中的特定行。
行分隔符区域显示文本文件中使用的回车格式。在 Windows 上,默认为 CRLF,代表回车换行。LF 是 Unix 和 Mac 机器上使用的标准格式,在 Git 中也是如此。如果您在 Windows 计算机上进行开发,当您将代码提交到存储库时,Git 通常会从 CRLF 转换到 LF。
文本格式区域描述用于源文件的文本编码。缺省值是 UTF-8,它是 ASCII 的超集,包含大多数西方字母,包括标准 Java 或 XML 文件中的任何字符。
文件访问指示器区域允许您在读/写和只读之间切换。未锁定的图标意味着编辑器中的当前文件具有读/写权限。锁图标表示编辑器中的当前文件是只读的。您可以通过单击指示器图标来切换这些设置。
“突出显示级别”按钮激活一个带有滑块的对话框,该对话框允许您设置希望在代码中看到的突出显示级别。
默认设置是 Inspections,它对应于皱眉的检查经理的图标。这个设置表明你应该准备好一些严厉的爱,因为检查经理将严格识别语法错误和代码中可能的问题,称为警告。您可以在标记栏中看到由 Inspections Manager 生成的一些黄色标记。
滑块上的下一个设置是语法,它对应于配置文件中检查管理器的图标。对于这种设置,检查经理对警告视而不见。语法模式没有检查模式严格,但仍然会突出显示会阻止代码编译的语法问题。
滑块上的最后一个突出显示模式是 None,它对应于一个微笑的检查经理的图标。这个图标让我觉得检查经理很开心,他根本不关心你的代码。在这种模式下,即使是最严重的语法错误也会被忽略,尽管当您试图构建时,编译器仍然会被它们卡住。我建议把重点放在检查上,并学会欣赏检查经理的严厉的爱。
常见操作
本节回顾 Android Studio 中使用的各种常见操作。如果您使用过像 Microsoft Word 这样的文本编辑器,您可能会对本节中介绍的功能很熟悉。
选择文本
正如您对任何优秀的文本编辑器所期望的那样,双击源文件中的任何单词都会选中它。此外,在字母或单词上单击并拖动光标会选择这些文本元素。将光标放在源文件中的任意位置,然后按 Shift+下箭头键或 Shift+上箭头键选择从光标处开始的文本行。在一行文本的任意位置连按三次会选择整行。按 Ctrl+A | Cmd+A 选择文件中的所有文本。
如果将光标放在任何单词内并按 Ctrl+W | Alt+向上键,则整个单词都将被选中。如果您继续按 Ctrl+W | Alt+向上箭头键,所选内容将无限扩大,以包括相邻的文本。如果您现在按 Ctrl+Shift+W | Alt+向下箭头键,选择范围将缩小。这种增长/收缩选择功能在 Android Studio 中被称为结构化选择。
使用撤消和重做
“撤消”和“重做”命令对于回滚和前滚有限数量的编辑操作非常有用。更改由特定的 UI 事件来限定,例如按 Enter 键或重新定位光标。撤消和恢复的键盘快捷键分别是 Ctrl+Z | Cmd+Z 和 Ctrl+Shift+Z | Cmd+Shift+Z。在工具栏的左边有紫色的左右箭头也可以做到这一点。Android Studio 的默认设置是记住你上次保存的所有步骤,或者最多 300 步。撤销和重做一次只应用于一个文件,所以回滚更改最有效的方法是使用 Git,这在第七章中讨论。
查找最近的文件
Android Studio 最好的特性之一是它能记住你最近处理过的所有文件。要激活此命令,请选择“查看➤最近的文件”或按 Ctrl+E | Cmd+E。出现的对话框允许您选择任何最近的文件,并在编辑器中将其作为选项卡打开。默认限制是最多记忆 50 个以前的文件。您可以通过导航到文件➤设置➤限制➤编辑器➤最近的文件限制来更改这些限制。
遍历最近的导航操作
Android Studio 还会记住你最近的导航操作。导航操作包括光标移动、选项卡更改和文件激活。若要遍历导航操作历史记录,请按 Ctrl+Alt+左箭头键| Cmd+Alt+左箭头键或 Ctrl+Alt+右箭头键| Cmd+Alt+右箭头键。请记住,导航操作不同于编辑操作;如果你想遍历你的编辑操作,你应该使用撤销和重做。
剪切、复制和粘贴
如果你使用过任何文本编辑器或文字处理器,你应该熟悉剪切、复制和粘贴。表 2-2 列出了这些基本命令,以及一些扩展的剪贴板命令。
表 2-2。
Cut, Copy, and Paste
| 命令 | 电脑钥匙 | Mac 密钥 | | --- | --- | --- | | 切口 | Ctrl+X | Cmd+X | | 复制 | Ctrl+C | Cmd+C | | 粘贴 | Ctrl+V | Cmd+V | | 扩展粘贴 | Ctrl+Shift+V | Cmd+Shift+V | | 复制路径 | Ctrl+Shift+C | Cmd+Shift+C | | 复制参考 | Ctrl+Alt+Shift+C | Cmd+Alt+Shift+C |除了操作系统剪贴板提供的简单剪切、复制和粘贴功能,Android Studio 还有一个扩展的剪贴板,可以记住最近五次剪切和复制操作。当你从 Android Studio 中剪切或复制文本时——或者在 Android Studio 运行时从几乎任何其他应用中剪切或复制文本时——Android Studio 会将这些文本放到一个堆栈中。要查看扩展的剪贴板堆栈,请按 Ctrl+Shift+V | Cmd+Shift+V。出现的对话框允许您选择要粘贴的项目。参见图 2-6 。
图 2-6。
Extended clipboard
您还可以通过导航到文件➤设置➤限制➤编辑器➤剪贴板中保留的最大内容数来更改扩展剪贴板堆栈的大小。您也可以通过右键单击所选内容并选择“与剪贴板比较”菜单项,将任何当前选定的文本与扩展剪贴板中最新元素的文本进行比较。
“复制路径”命令 Ctrl+Shift+C | Cmd+Shift+C 复制在“项目”或“管理器”工具窗口或编辑器的任何选项卡中选择的任何文件或目录的完全限定的操作系统路径。复制路径对于终端会话中的操作特别有用。
使用复制引用 Ctrl+Alt+Shift+C | Cmd+Alt+Shift+C,Android Studio 允许您复制对方法、变量或类的逻辑引用。当您将这个引用粘贴到另一个源文件中时,Android Studio 会自动包含任何必需的包限定符和导入。您还可以在“项目”和“管理器”工具窗口中对包、目录和文件使用通用的剪切、复制和粘贴来代替鼠标操作(如拖放),以便重新组织资源在项目中的位置。
上下文菜单
在 IDE 上右键单击(在 Mac 上按住 Ctrl 键单击)可以激活许多上下文菜单。您已经在上一节中探索了编辑器选项卡上下文菜单。Android Studio 中的大多数窗格、图标和栏都会生成一个上下文菜单,如果你右击它(在 Mac 上是 Ctrl-click)。Android Studio 最大的特点之一是动作可以用多种方式执行。这种冗余意味着你可以根据自己的喜好自由发展自己的技能和习惯。我发现对最频繁的操作使用键盘快捷键,对不太频繁的操作使用菜单和上下文菜单操作是与 Android Studio 交互的最有效方式。现在,通过右键单击(在 Mac 上按住 Ctrl 键单击)IDE 中的栏、选项卡、窗格和文件来浏览上下文菜单。
获得帮助
Android Studio 中的帮助菜单有几个有用的菜单项。find Action(Ctrl+Shift+A | Cmd+Shift+A)是你在 Android Studio 中获取帮助最常用的命令。该命令会激活一个对话框,允许您在 Android Studio 中搜索任何功能。按 Ctrl+Shift+A | Cmd+Shift+A 并在搜索框中键入显示行号。现在使用箭头键选择设置,并按下回车键。在设置窗口中,选择编辑器➤外观。您应该看到“显示行号”复选框。
选择帮助➤在线文档是你的所有 Android Studio 技术规范的来源。这是 Android Studio 最全面的文档。此外,帮助➤默认键映射参考菜单项是一个有用的参考。当你学习使用 Android Studio 时,你可以考虑打印这个 PDF 文件并把它放在附近。
使用键盘导航
键盘可能是在 Android Studio 中导航的最强大的方式。从主菜单栏中选择导航菜单以检查其内容。本节讨论导航菜单中最重要的菜单项(如表 2-3 所示)及其相应的键盘快捷键。后续章节讨论其他菜单项。
表 2-3。
Keyboard Navigation
| 命令 | 电脑钥匙 | Mac 密钥 | | --- | --- | --- | | 在中选择 | Alt+F1 | Alt+F1 | | 班级 | Ctrl+N | Cmd+O | | 文件 | Ctrl+Shift+N | Cmd+Shift+O | | 线条 | Ctrl+G | Cmd+L | | 相关文件 | Ctrl+Alt+Home | alt+Cmd+向上箭头 | | 上次编辑位置 | ctrl+Shift+退格键 | cmd+Shift+退格键 | | 类型层次结构 | Ctrl+H | Ctrl+H | | 申报 | Ctrl+B | Cmd+B |在中选择
Android Studio 最好的一个特性就是导航是双向的。您已经看到了如何从各种工具窗口中打开/激活作为编辑器选项卡的文件。现在,您将学习如何从编辑器导航到各种工具窗口。
按 Alt+F1。这将激活“在上下文中选择”菜单,该菜单包含几个菜单项,包括“项目视图”、“收藏夹”和“文件结构”。单击“项目视图”选项。项目工具窗口被激活,对应于编辑器的活动选项卡的文件被突出显示,并且该文件的任何父目录被切换打开。Android 项目往往有很多文件素材;因此,在中使用 Select 是您将掌握的最重要的技能之一。
班级
类操作允许您导航到特定的 Java 类。值得注意的是,这个操作只搜索 Java 源文件,或者 Java 源文件的内部类。按 Ctrl+N | Cmd+O,开始输入 act。Android Studio 已经为你的所有文件建立了索引,所以它会为你提供一个可能匹配的列表,最可能匹配的会高亮显示。你所需要做的就是按回车键打开MainActivity.java
。
文件
文件操作允许您导航到项目中的任何文件。如果您正在项目中寻找一个 XML 文件,这就是您想要使用的操作。按 Ctrl+Shift+N | Cmd+Shift+O,开始输入 act。我们特意使用了相同的搜索术语 act 来说明“导航➤”文件的更大范围。注意,搜索结果包括 Java 源文件MainActivity.java
以及任何其他文件,比如activity_main.xml
。使用箭头键选择activity_main.xml
并按 Enter 键打开它。
线条
行操作 Ctrl+G | Cmd+L 激活一个对话框,允许您导航到源文件的特定行:列。如果你在弹出的“转到第一行”对话框中输入一个简单的整数,然后按“确定”, Android Studio 会跳到那一行,而不考虑第几列。
相关文件
相关的文件动作 Ctrl+Alt+Home | Alt+Cmd+向上箭头是 Android Studio 中最有用的命令之一。Android 项目通常有很多相关文件。例如,一个简单的 Android 活动通常至少有一个相应的 XML 布局文件来呈现活动的布局,还有一个相应的 XML 菜单文件来呈现活动的菜单。当您处理片段时,这种复杂性只会增加。您已经看到了如何使用收藏夹将相关文件分组在一起。通过导航➤相关文件,你可以查询 Android Studio 来显示相关文件。激活MainActivity.java
标签后,按 Ctrl+Alt+Home | Alt+Cmd+上箭头键。您应该会看到activity_main.xml
列在那里。使用箭头键选择它,然后按 Enter 键。
上次编辑位置
最后一次编辑位置操作 Ctrl+Shift+back space | Cmd+Shift+back space 允许您导航到最后一次编辑。如果您继续激活此命令,光标将移动到您上次编辑的文件/位置,依此类推。
类型层次结构
Android 使用 Java,一种面向对象的编程语言。任何面向对象语言的标志之一是继承,这有利于代码重用和多态。当编辑器中的MainActivity.java
文件处于活动状态时,按 Ctrl+H 切换打开层次工具窗口。在那里你会看到一系列层叠的对象,所有这些对象都可以追溯到 Java 中所有对象的祖先Object
。请记住,只有当编辑器中的活动选项卡是 Java 源文件时,导航➤类型层次结构操作才有效。
申报
声明操作允许您跳转到方法、变量和资源的原始定义。激活此操作的另一种方法是按住 Ctrl|Cmd 键,同时将鼠标滚动到文件中的方法、变量或资源上。如果元素带有下划线,您可以通过在按住 Ctrl|Cmd 键的同时左键单击该元素来导航到它的声明。在MainActivity.java
中,点击方法setContentView(...)
中的任意位置,然后按 Ctrl+B | Cmd+B。您将立即被带到这个方法的声明,它位于MainActivity
的一个超类ActionBarActivity.java
中。
查找和替换文本
查找和替换文本是编程的一个重要部分,Android Studio 有一套强大的工具来帮助你做到这一点。本节涵盖了一些最重要的工具。表 2-4 为你列出。
表 2-4。
Find and Replace
| 命令 | 电脑钥匙 | Mac 密钥 | | --- | --- | --- | | 发现 | Ctrl+F | Cmd+F | | 在路径中查找 | Ctrl+Shift+F | Cmd+Shift+F | | 替换 | Ctrl+R | Cmd+R | | 在路径中替换 | Ctrl+Shift+R | Cmd+Shift+R |发现
Find 动作用于查找单个文件中出现的文本。在MainActivity.java
中,按 Ctrl+F | Cmd+F 调出一个出现在编辑器顶部的搜索栏。在搜索栏的搜索框中键入 action。您会注意到action
在整个文件中立即以黄色突出显示。您还会注意到标记栏中的绿色小记号,指示找到的文本的位置。将鼠标滚动到查找栏上的双右箭头上会显示高级搜索选项。
在路径中查找
“在路径中查找”动作允许您在比前面描述的“查找”动作更大的范围内进行搜索。您也可以使用正则表达式,并用文件掩码分隔结果。按 Ctrl+Shift+F | Cmd+Shift+F,并在编辑器顶部搜索栏的搜索框中键入 hello。默认情况下,“查找路径”中的搜索范围设置为“整个项目”,尽管您可以将搜索范围限制为特定的目录或模块。接受缺省值“整个项目”,然后单击“查找”按钮。结果显示在“查找工具”窗口中。在“查找工具”窗口中单击一个条目会立即将包含的文件作为编辑器的一个新选项卡打开,并跳转到该事件。
替换
替换操作 Ctrl+R | Cmd+R 用于替换单个文件中的文本,替换功能是查找的超集。替换文本的更安全的方法是使用重构➤重命名命令,我们将在后面介绍。
在路径中替换
“在路径中替换”操作 Ctrl+Shift+R | Cmd+Shift+R 是“在路径中查找”的超集。然而,使用重构➤重命名几乎总是比在路径中使用替换更好,所以使用这个命令要非常小心,因为你可能会引入错误。
摘要
在本章中,我们已经讨论了编辑器和聚集在编辑器周围的工具窗口。我们已经讨论了如何使用工具按钮和重新定位它们。我们还讨论了用于导航的工具窗口和 IDE 的主要 UI 元素,包括主菜单栏、工具栏、状态栏、装订线和标记栏。我们还讨论了如何使用菜单和键盘快捷键,以及使用查找和替换来搜索和导航。最后,我们讨论了如何使用 Android Studio 中的帮助系统。最重要的是,我们已经在 Android Studio 中建立了一个 UI 元素词典,我们将在后续章节中引用它。
三、在 Android Studio 中编程
本章讲述了如何在 Android Studio 中编写和生成代码。Android Studio 利用其面向对象编程的知识来生成极其相关且格式良好的代码。本章涵盖的功能包括覆盖方法、用 Java 块包围语句、使用模板插入代码、使用自动完成、注释代码和移动代码。如果你阅读这本书的目标是掌握 Android Studio,你会想要特别关注这一章,因为这里描述的工具和技术将对你的编程效率产生最大的影响。
我们开始吧。如果您在第一章中创建的 HelloWorld 应用尚未打开,请立即打开它。
使用代码折叠
代码折叠是节省编辑器屏幕空间的一种方式。代码折叠允许您隐藏特定的代码块,以便您可以专注于您感兴趣的那些代码块。如果MainActivity.java
没有打开,按 Ctrl+N | Cmd+O 并键入 Main 将其打开。按 Enter 键打开MainActivity.java
类,如图 3-1 所示。
图 3-1。
Use the Enter Class Name dialog box to open MainActivity.java
如果默认情况下不显示行号,请导航以帮助➤找到操作。键入显示行号并选择显示行号活动编辑器选项,如图 3-2 所示。
图 3-2。
Use the Enter Action or Option Name dialog box to show line numbers
当你观察MainActivity.java
中的行号时,你会注意到一些奇怪的事情:行号不是连续的。在图 3-3 中,行号从 1、2、3 开始,然后跳到 7、8、9。仔细看图 3-3 中的第 3 行。您会注意到在 import 语句的左边有一个加号,后面有一个省略号。如果您仔细查看自己的代码,您还会注意到省略号以淡绿色突出显示。所有这些视觉元素都在告诉你,Android Studio 隐藏了一段已经折叠的代码。
图 3-3。
Folded block of code at the import statement
一条称为折叠轮廓的细虚线位于左边距的长度方向,在灰色装订线和白色编辑器之间。折叠轮廓可以包含三个图标:包围在方框中的加号图标(如图 3-3 的第 3 行)和上下箭头,上下箭头内有水平线(见图 3-3 的第 12 行和第 15 行)。向下箭头表示可折叠代码块的开始,而向上箭头表示可折叠代码块的结束。如上所述,加号框表示代码块已经被折叠。单击这些图标中的任何一个都可以将相应的块切换到折叠或展开状态。表 3-1 包含所有代码折叠操作的描述和键盘快捷键。
表 3-1。
Code-Folding Options
| [计]选项 | 电脑钥匙 | Mac 密钥 | 描述 | | --- | --- | --- | --- | | 发展 | ctrl+数字加 | cmd+数字加 | 展开光标所在的折叠块 | | 倒塌 | ctrl+数字-减号 | cmd+数字-减号 | 折叠光标所在的展开块 | | 全部展开 | ctrl+Shift+数字加 | cmd+Shift+数字加 | 展开窗口中的所有代码 | | 全部折叠 | ctrl+Shift+数字-减号 | cmd+Shift+数字-减号 | 折叠窗口中的所有代码 | | 切换折叠 | ctrl+句点 | cmd+句点 | 折叠/展开光标所在的块 |将光标放在MainActivity.java
的onCreate()
方法内的任何地方。现在按几次 Ctrl+句点| Cmd+句点来切换此块的展开和折叠。还可以尝试使用展开键盘快捷键 Ctrl+Numeric-Plus | Cmd+Numeric-Plus 和折叠键盘快捷键 Ctrl+Numeric-Minus | Cmd+Numeric-Minus。
最后,通过单击折叠轮廓中的代码折叠图标,使用鼠标切换折叠和展开的块。请记住,为了节省屏幕空间,折叠单个块、多个块甚至文件中的所有块只是将它们从视图中删除。然而,编译器仍然会在您构建时尝试编译它们。同样,折叠包含有问题或错误代码的块不会从标记栏中删除任何警告或错误。您可以通过选择菜单选项设置➤编辑器➤代码折叠来更改代码折叠选项。
执行代码完成
大多数当代 ide 都提供某种形式的代码完成,Android Studio 也不例外。Android Studio 随时准备提供帮助,即使你没有主动寻求帮助。在实践中,这意味着 Android Studio 会在你输入的时候默认建议各种选项来完成你的代码。Android Studio 生成的建议列表并不总是完美的,但是这些建议是根据最佳实践排序的,并且它们通常符合适当的命名约定。Android Studio 对 Android SDK 和 Java 编程语言都非常了解;事实上,它可能比你更了解这些学科。如果你带着谦逊和渴望学习的态度来使用这个工具,不管你以前的编程经验如何,你最终都会看起来像一个摇滚明星。
代码完成特性是上下文相关的,因为根据光标的范围,提供给你的建议会有所不同。如果您在类范围内键入代码,代码完成建议将与您在方法范围内键入的建议不同。即使您选择不接受代码补全建议,出于上述原因,您也应该注意它们。
表 3-2 列出了 Android Studio 中的四种代码补全:
表 3-2。
Code-Completion Options
| [计]选项 | 电脑钥匙 | Mac 密钥 | 描述 | | --- | --- | --- | --- | | 默认 | 没有人 | 没有人 | 默认代码完成行为。Android Studio 会在您输入时在光标旁边显示一个建议列表。您可以使用上下箭头键在建议列表中的条目间导航,并使用 Enter 键选择一个条目。 | | 基础 | ctrl+空格 | ctrl+空格 | 基本代码完成功能类似于默认代码完成,但也在当前选定的条目旁边显示 Javadoc 窗口。单击 Javadoc 窗口中的向上箭头图标会显示详细的文档。 | | 智能类型 | ctrl+Shift+空格键 | ctrl+Shift+空格键 | SmartType 代码完成功能类似于 Basic,但会生成一个更具选择性和相关性的建议列表。 | | 循环扩展字 | Alt+/ | Alt+/ | 提供文档中已经使用过的单词。循环往复。 | | 循环扩展字(向后) | Alt+Shift+/ | Alt+Shift+? | 提供文档中已经使用过的单词。循环下降。 |- 一旦您开始键入,默认代码自动完成。
- 基本代码完成的行为类似于默认代码完成,但还会在建议列表中当前所选项的旁边显示一个 Javadoc 窗口。
- SmartType 代码完成也显示 Javadoc,但也生成更具选择性和相关性的建议列表。
- 循环展开单词循环显示源文档中已经使用的单词,并允许您选择它们。
让我们开始编码来演示代码完成是如何工作的。右键单击(在 Mac 上按住 Ctrl 键)包com.apress.gerber.helloworld
并选择新建➤ Java 类,弹出新建类对话框,如图 3-4 所示。将该类命名为 Sandbox,然后单击“确定”。
图 3-4。
Create New Class dialog box
在Sandox.java
中Sandbox
类的括号内,通过输入 private Li 开始定义成员,如图 3-5 所示。将出现一个代码完成菜单,其中列出了可供您完成代码的可能选项。使用上下箭头键导航代码完成菜单。用向下箭头键选择List<E>
选项,然后按回车键。
图 3-5。
A code-completion menu appears when you start typing
Android Studio 中的默认行为是在开始输入时显示代码完成建议列表。您不需要激活任何键盘快捷键来调用默认代码完成—它会自动发生。你现在应该有一行代码显示为private List
,如图 3-6 所示。直接在单词List
后面,键入用于在 Java 中定义泛型的左尖括号(<)。请注意,Android Studio 用一个右尖括号来结束括号子句,并将光标放在括号内。
图 3-6。
Code completion of a list with String as the generic
在尖括号内键入 Str,然后按 Ctrl+Space 调用基本代码完成。您会注意到,在建议列表中当前选定的项目(String
)旁边会出现一个 String Javadoc 窗口的文档。滚动 Javadoc 窗口查看String
的 Javadoc 文档。单击 Javadoc 窗口中的向上箭头,在默认浏览器中显示String
的详细 API 文档。返回 Android Studio,选择String
作为通用类,通过按回车键定义List<String>
时使用。
Android Studio 最好的特性之一就是它会为你建议变量名。在private List<String>
后直接输入一个空格,按 Ctrl+Space 激活基本代码补全。Android Studio 生成了一个建议列表,但是没有一个变量名具有足够的描述性,所以改为键入 mGreetings。小写的m
代表成员(也称为字段),在类成员名前面加上m
是 Android 中的命名约定。同样,静态类成员的前缀是小写的s
。您不需要遵循这种命名约定,但是如果您这样做,您的代码将更容易被他人理解。请记住,局部(方法作用域)变量不遵循m
和s
前缀命名约定。
修改您的代码行,使其现在显示为private List<String> mGreetings = new
。通过按 Ctrl+Shift+Space 调用 SmartType 代码完成。选择ArrayList<>()
完成该语句,包括终止分号,如图 3-7 所示。SmartType 代码完成类似于基本代码完成,只是在建议列表中生成项目时,它考虑的变量范围比默认和基本代码完成更广。例如,在赋值操作符的右侧使用 SmartType 代码完成时,建议列表通常会包含相关的工厂方法。
图 3-7。
SmartType code completion Note
如果您在 Android Studio 中的 JDK 设置为 7 或更高,那么代码完成生成的代码可能会使用菱形符号。例如,ArrayList<String>
可能以ArrayList<>
的形式出现在使用泛型的赋值语句的声明的右侧,如图 3-7 所示。
循环展开词有个花里胡哨的名字,其实很简单。按住 Alt 键,同时按几次正斜杠,调用循环展开 Word。提供给您的单词与您的文档中出现的单词相同。当你循环阅读单词时,注意黄色的高亮部分。现在通过按住 Alt 和 Shift 键同时按下正斜杠(Mac 上的问号)几次来调用循环向后展开单词。请注意,提供/突出显示的单词现在向下循环并远离光标,而不是向上循环并远离光标。
注释代码
如果你曾经做过任何编程,你就会知道注释是被编译器忽略的代码行,但是它包含了对编码者和他们的合作者来说很重要的信息和元数据。注释可以是以两个正斜杠开始的行注释,也可以是以一个正斜杠和一个星号开始并以一个星号和一个正斜杠结束的块注释。从主菜单中,您可以通过选择代码➤注释来激活注释。然而,激活注释的最佳方式是使用表 3-3 中列出的键盘快捷键。
表 3-3。
Commenting Options
| [计]选项 | 电脑钥匙 | Mac 密钥 | 描述 | | --- | --- | --- | --- | | 切换注释行 | Ctrl+/ | Cmd+/ | 使用 Java 行注释样式(例如// …)在注释或取消注释之间切换行。您可以通过选择这些行将此操作应用于多行。 | | 切换注释块 | Ctrl+Shift+/ | Alt+Cmd+/ | 使用 Java 块注释样式(如/* … */)在注释块和未注释块之间切换选定的文本。将注释块应用到所选文本将包括注释块中的所有所选文本。 |在mGreetings
声明上方键入 refactor initial ization to constructor。按 Ctrl+/ | Cmd+/将此文本转换为注释,如图 3-7 所示。使用快捷键 Ctrl+/ | Cmd+/,尝试打开和关闭此注释。
使用代码生成
如果使用得当,代码生成将会为您节省最多的时间。代码生成有能力为你生成各种各样的方法,包括构造器、getters、setters、equals()
、hashCode()
、toString(),
等等。
在使用代码生成之前,让我们验证 Android Studio 是否被正确配置为忽略成员名前缀m
和s
。单击文件➤设置➤代码样式➤ Java ➤代码生成打开设置对话框,其中代码生成选项卡处于选中状态。如果字段和静态字段文本框没有分别包含 m 和 s,现在在那里输入,点击应用,然后点击确定,如图 3-8 所示。
图 3-8。
Adding m and s to Field and Static Field in the Code Generation tab
构造器
将光标放在Sandbox.java
的类范围内。要在 Android Studio 中生成构造函数,按 Alt+Insert | Cmd+N,选择构造函数。如图 3-9 所示,选择由构造函数初始化的字段对话框允许你选择类成员作为参数。我们需要一个无参数的构造函数,所以单击“不选”按钮。在 Java 中,重载构造函数以接受不同类型和数量的参数是很常见的。例如,您可以再次调用这个对话框,生成一个构造函数,它将一个List<String>
作为参数,并将这个参数赋给我们的成员mGreetings:List<String>
。
图 3-9。
Choose Fields to Initialize by Constructor dialog box
getter/setter
Java 类通常是封装的,这意味着类成员通常被声明为私有的,这些成员的公共接口是通过公共访问器(getter)和公共赋值器(setter)方法提供的。单击将光标放在Sandbox.java
的类范围内,然后按 Alt+Insert | Cmd+N。您会注意到,有一个 Getter 选项,一个 Setter 选项,以及一个 Getter 和 Setter 选项。Getter 和 setter 方法通常是成对出现的,所以除非你有充分的理由省略其中的一个,否则最好同时生成两个方法。从列表中选择 Getter 和 Setter,如图 3-10 所示。在随后的“选择字段以生成 Getters 和 Setters”对话框中,从列表中选择mGreetings:List<String>
并单击“确定”。你的类现在有了一个mGreetings
的 getter 和 setter,如图 3-11 所示。注意,在生成方法名时,生成的代码忽略了前缀m
,因为您在之前的设置中声明了前缀m
和s
。
图 3-11。
Generated getter and setter methods
图 3-10。
Generating the getter and setter
覆盖方法
代码生成理解类的层次结构,因此您可以覆盖任何超类或实现的接口中包含的方法。Sandbox.java
是一个简单明了的老式 Java 对象(POJO)。现在修改Sandbox
类,使其扩展RectShape
。当您键入 extends RectShape 时,单词RectShape
可能会以红色突出显示。如果是这种情况,按 Alt+Enter 导入RectShape
类,如图 3-12 所示。
图 3-12。
Extending the superclass
如果您通过按 Ctrl+H 调用层次视图,您将看到以RectShape
、Shape
和Object
为其祖先的Sandbox
的类层次,正如您通过检查图 3-13 所看到的。现在按 Alt+Insert | Cmd+N 并选择覆盖方法。让我们从Shape
开始覆盖hasAlpha()
方法,如图 3-14 所示。从版本 Java 5 开始的惯例是用@Override
注释被覆盖的方法,所以让我们保持 Insert @Override 复选框处于选中状态。@Override
注释告诉编译器验证方法的名称和签名,以确保该方法确实被覆盖。修改hasAlpha()
的返回语句,使其总是返回true
。
图 3-14。
Modifying the hasAlpha( ) method
图 3-13。
Selecting methods to override/Implement with RectShape
toString()方法
Android Studio 可以为你生成toString()
方法。让我们为Sandbox
创建一个toString()
方法,并包含mGreetings
成员。按 Alt+Insert | Cmd+N,选择toString()
。选择您唯一的成员mGreetings
,然后单击确定。Android Studio 生成一个返回字符串如"Sandbox{" + "mGreetings=" + mGreetings + '}'
,如图 3-15 。如果在我们的类中有多个成员并选择了它们,它们也会被附加到这个方法的返回字符串中。当然,toString()
生成的代码并不是一成不变的;您可以随意更改这个方法,只要它返回一个String
。
图 3-15。
Generate the toString( ) method
委托方法
Android Studio 知道您的类成员,因此允许您将行为从类中定义的代理方法委托给类成员的方法。这听起来很复杂,但很简单。为了向您展示委托方法选项是如何工作的,让我们直接进入代码。
在Sandbox.java
中,将光标放在类范围内。按 Alt+Insert | Cmd+N,然后选择委托方法。选择mGreetings:List<String>
并按下 OK。List 接口有许多方法,您可以将行为委托给这些方法。为简单起见,选择add(object:E):boolean
,如图 3-16 所示。如果您想要委托多个方法,请在选择这些方法时按住 Ctrl 键(Mac 上为 Cmd 键)。单击确定。
图 3-16。
Selecting methods to generate delegates
生成的add()
methodin Sandbox.java
现在是一个代理,将行为委托给mGreetings
成员的add()
方法,如图 3-17 所示。注意,add()
方法的参数被定义为一个String
,以匹配mGreetings
的通用定义List<String>
。委托方法不是被覆盖的方法,所以你可以把你的代理方法重命名为任何你想要的名字,但是名字add()
很有意义,所以继续保持这个名字。
图 3-17。
Generated add( ) method
插入实时模板
Android Studio 附带了许多模板,允许您将预定义的代码直接插入到源文件中。在许多 ide 中,生成的代码只是从一个模板粘贴过来的,不考虑作用域;然而,Android Studio 的模板是范围感知的,也可以集成可变数据。
在您开始使用 Android Studio 中的实时模板之前,让我们探索现有的实时模板并创建一个我们自己的模板。导航到文件➤设置➤实时模板。选择普通模板组。现在单击右上角的绿色加号按钮,并选择 Live Template。填充缩写、描述和模板文本字段,如图 3-18 所示。在应用此模板之前,您必须单击 Define 按钮,该按钮看起来像窗口底部的蓝色超文本链接。现在选择 Java 并选择所有的作用域(语句、表达式、声明等等)。单击应用。
图 3-18。
Create a live template called cb (comment block)
您刚刚创建了一个名为cb
的定制 live 模板,它在任何 Java 源文件和任何范围内编码时都是可用的。图 3-18 中的红色字$SELECTION$
为变量。您将很快看到这个变量的作用。现场模板选项在表 3-4 中描述。
表 3-4。
Live Template Options
| [计]选项 | 电脑钥匙 | Mac 密钥 | 描述 | | --- | --- | --- | --- | | 插入实时模板 | Ctrl+J | Cmd+J | 调用范围敏感的实时模板列表。将在您的文档中插入模板代码。 | | 用实时模板包围 | Ctrl+Alt+J | Cmd+Alt+J | 使用实时模板列表调用范围敏感的包围。将用一个范围敏感的实时模板包围所选内容。 |在离开实时模板的设置页面之前,快速浏览一下位于普通模板组中的一个现有实时模板,其缩写为 psfs。单击 psfs 检查其内容。您会注意到这个模板生成了一个带有public static final String
的String
常量,并且它只在 Java 和 Groovy 声明范围内可用。单击“确定”返回编辑器。
在Sandbox.java
的声明部分,在mGreetings
的定义下,键入 psfs,然后通过按 Ctrl+J | Cmd+J 调用实时模板,然后按 Enter。通过给该常量一个名称和赋值来完成该语句,如下所示:public static final String HELLO = " HELLO Sandbox ";。
Note
在 Java 中,常量的命名约定是全部大写。
在构造函数上方,键入单词 CONSTRUCTORS。现在将这个单词转换成一个注释块,以引起其他程序员的注意。选择整个单词,“构造函数”,然后按 Ctrl+Alt+J | Cmd+Alt+J 调用“用实时模板包围”。在 Live Templates 列表中选择 cb,按回车键,如图 3-19 所示。您刚刚应用了之前创建的实时模板。
图 3-19。
Apply the live template called cb (comment block)
移动您的代码
Android Studio 了解代码块是如何分隔的,因此移动代码行或代码块既简单又直观。Move 语句和 Move Line 的区别在于,Move 语句同时考虑边界和范围,而 Move Line 则两者都不考虑。如果选择用 move 语句移动代码语句,该语句将保留在其封闭块范围的边界内。如果你用 Move Line 移动同一个语句,Android Studio 会把这个语句当作一个简单的文本行,并把它移动到你想要它去的任何地方。
您也可以移动整个代码块。使用 Move 语句,您只需将光标放在要移动的块的起始行(带大括号的行)上的任意位置,然后按 Ctrl+Shift+Down | Cmd+Shift+Down 或 Ctrl+Shift+Up | Cmd+Shift+Up。整个区块将一起移动,同时尊重其他区块的边界,并保持在其封闭范围的边界内。“移动行”不理解范围或边界,但在应用“上移行”或“下移行”操作之前,您仍然可以通过先选择它们来移动多行,这两种操作在 PC 和 Mac 上分别是 Alt+Shift+上移和 Alt+Shift+下移。
要理解 Android Studio 中的 move 操作,最好直接去做。让我们从在我们的add()
方法中创建一个语句开始。在显示return mGreetings.add(object);
的那一行之后,按 Enter 键开始新的一行,并键入 soutm。然后按 Ctrl+J | Cmd+J 调用 Live Template,产生System.out.println("Sandbox.add");
。您可能已经注意到,您的新代码行将不会到达,因为 return 语句在它上面,如图 3-20 所示。让我们用 move 语句上移这个语句。按住 Ctrl|Cmd 和 Shift 的同时,多次按向上箭头键。Android Studio 重新定位该语句,但不会让您意外地将该语句移动到可能没有任何意义的范围内。使用移动线(Alt+Shift+Up)再次尝试此操作,并再次观察其行为。
图 3-20。
Move Statement and Move Line
让我们尝试另一个例子,通过将你的构造函数移到类的底部来展示 Move 语句的强大功能。确保在Sandbox()
声明和它上面的注释块之间没有空行。现在,将光标放在Sandbox()
的声明行上的任意位置,通过按住 Ctrl|Cmd 和 Shift 键并重复按下向下箭头键来调用 Move Statement Down,直到您的构造函数是类中的最后一个方法。请注意,包括注释在内的整个块都跳到了类的底部,同时避开了其他方法。表 3-5 描述了移动代码操作及其键盘快捷键。
表 3-5。
Move Code Options
| [计]选项 | 电脑钥匙 | Mac 密钥 | 描述 | | --- | --- | --- | --- | | 下移语句 | ctrl+Shift+向下 | Cmd+Shift+Down | 在范围边界内向下移动一条或多条语句。如果移动一个块,整个块将一起跳到下一个语法正确的位置。 | | 将语句上移 | ctrl+Shift+向上 | cmd+Shift+向上 | 与下移语句相同,但上移。 | | 下移一行 | Alt+Shift+Down | Alt+Shift+Down | 向下移动语句或行。不遵守范围边界或语法。 | | 向上移动一行 | Alt+Shift+Up | Alt+Shift+Up | 与下移一行相同,但上移。 |设计您的代码
代码风格约定不断发展。对于在方法后面应该放置多少空格,或者左大括号应该出现在方法签名的同一行还是紧接在方法签名的下面,没有严格的规则。组织倾向于定义他们自己的代码风格,但是代码风格也因程序员而异;您也可能有一种自己喜欢的代码风格。幸运的是,Android Studio 使得设计和组织代码变得简单。在开始设计代码样式之前,让我们检查一下代码样式的设置。选择文件➤设置➤码样式,弹出设置对话框,如图 3-21 所示。Java 和 XML 是我们对 Android 最感兴趣的语言。在左窗格中切换打开代码样式,选择 Java,并检查设置窗口中的每个选项卡。
图 3-21。
Settings dialog box with Code Style ➤ Java selected and showing the Wrapping and Braces tab
通过选择/取消选择各个选项卡中间窗格中的复选框来试验这些设置,并注意右窗格中的示例类如何相应地改变以适应您的风格。单击顶部的“管理”按钮,定义一个新方案。现在点击另存为,给你的方案起个名字,比如 android,然后点击确定。如果您对已保存的方案做了进一步的更改,请单击“应用”按钮来应用这些更改。当您使用 Ctrl+Alt+L | Cmd+Alt+L 设置代码格式时,将应用您在代码样式选项卡中选择的设置。表 3-6 中描述了代码组织选项。
表 3-6。
Code-Organizing Options
| [计]选项 | 电脑钥匙 | Mac 密钥 | 描述 | | --- | --- | --- | --- | | 自动缩进行 | Ctrl+Alt+I | Ctrl+Alt+I | 根据方案设置对当前选定的一行或多行应用缩进。 | | 优化导入 | Ctrl+Alt+O | Ctrl+Alt+O | 从 import 语句中删除任何未使用的导入。Android Studio 非常注意保持导入的干净和相关性,这个命令实际上是多余的。 | | 重新排列代码 | 没有人 | | 根据排列设置中建立的规则重新排列代码元素的顺序。 | | 重新格式化代码 | Ctrl+Alt+L | Cmd+Alt+L | 为特定方案应用代码样式设置。 |自动缩进行
自动缩进行对于在编码时保持行的正确缩进很有用。Java 中控制制表符和缩进的规则可以通过文件➤设置➤代码样式➤ Java ➤制表符和缩进来访问。自动缩进行应用于当前行,或者如果您选择了多行,则应用于所有选定的行。
在Sandbox.java
中,选择整个方法代码块并按 Tab 键。该块应该向右移动一个制表符的距离。现在将光标放在该块的第一行,并在 PC 和 Mac 上按 Ctrl+Alt+I。您会注意到,自动缩进会将该行重新定位到适当的缩进位置,尽管方法块的其余部分不受影响。现在,通过按 Ctrl+A | Cmd+A 选择该类中的所有代码,并再次按 Ctrl+Alt+I。这一次,将对整个文件应用适当的缩进。
重新排列代码
排列决定了代码中元素的顺序。例如,大多数人喜欢将类成员声明放在类的顶部,然后是构造函数,最后是 getters 和 setters,等等。您可以通过文件➤设置➤代码风格➤ Java ➤排列访问排列选项卡,编辑排列设置。
在上一节中,您将构造函数移到了类的底部。这通常不属于它的位置。从主菜单中选择代码➤重排代码。你会注意到你的构造函数已经回到了它的预期位置,在声明部分的下面。重排代码根据排列设置中的规则执行此重排操作。
重新格式化代码
重新格式化代码是最强大的代码样式操作,因为它为您提供了应用代码样式设置中定义的所有代码样式选项的选项。正如你已经看到的,代码风格设置可以从主菜单通过文件➤设置➤代码风格。此外,重新格式化代码允许您重新格式化当前选定的文件,或相同类型和目录的每个文件。此外,重新格式化代码允许你链接重排条目(这将在 Java 文件上应用重排代码),并优化导入到命令中,如图 3-22 所示。尝试通过按 Ctrl+Alt+L | Cmd+Alt+L 来重新格式化Sandbox.java
。
图 3-22。
Reformat Code dialog box with Rearrange Entries selected
围绕着
Surround With(Ctrl+Alt+T | Cmd+Alt+T)是 Live Template(Ctrl+Alt+J | Cmd+Alt+J)中功能的超集。但是,Surround With 还包括用 Java 块包围所选语句的选项,例如if/else
、for
、try/catch
等等。虽然你的沙箱类中的简单代码不会威胁抛出任何检查过的异常,但是用try/catch
块包围威胁抛出异常的语句是最好的环绕应用之一;这可能就是为什么快捷键 Ctrl+Alt+T | Cmd+Alt+T 中包含一个 T 的原因。环绕操作如表 3-7 所示。
表 3-7。
Surround With Options
| [计]选项 | 电脑钥匙 | Mac 密钥 | 描述 | | --- | --- | --- | --- | | 用...包围 | Ctrl+Alt+T | Cmd+Alt+T | 用 Java 代码块将所选语句括起来,如 if/else、for、try/catch 等。 | | 展开/移除 | Ctrl+Shift+Delete | Cmd+Shift+Delete | 从选定的一条或多条语句中解开代码块。 |在Sandbox.java
的add()
方法中,您希望确保没有重复。如图 3-23 所示,用if/else
块将返回的mGreetings.add(object);
围住。选择整行并按 Ctrl+Alt+T | Cmd+Alt+T 激活环绕。现在从菜单中选择if/else
。在if
语句的括号中,键入!mGreetings.contains(object)并且在 else 块类型中返回 false。
图 3-23。
Wrapping and unwrapping blocks of code with Surround With
假设您的业务规则已经改变,您不再关心mGreetings
中的重复条目。使用展开/移除来移除您刚刚创建的if/else
块。将光标放在return mGreetings.add(object);
语句的任意位置,按 Ctrl+Shift+Delete | Cmd+Shift+Delete,选择unwrap if
。该方法现在看起来应该和您修改它之前一样。
Surround With 的另一个伟大应用是迭代集合。在上一节中,您自动生成了一个toString()
方法。现在修改这个方法,以便迭代mGreetings
集合。从toString()
方法中删除 return 语句,这样toString()
方法的主体就是空的。现在键入 mGreetings,然后按 Ctrl+Alt+T | Cmd+Alt+T。从列表中选择Iterate Iterable
,或者按 I 键。再次按回车键接受greeting
作为单个元素的名称。产生的代码是一个for-each
循环。注意,Android Studio 理解mGreetings
包含Strings
,并且它还生成了一个名为greeting
的局部变量,其单数形式为mGreetings
减去m
。根据图 3-24 进一步修改add()
方法。
图 3-24。
Using Surround With to iterate an iterable
摘要
本章介绍了 Android Studio 最重要的代码生成特性。我们建议您返回文件➤设置➤代码样式➤ Java 和文件➤设置➤代码样式➤,并花几分钟时间探索那里的各种设置。Android Studio 为编码提供了很多键盘快捷键,但你不必全部记住。如果你不知所措,你可以使用这本书作为参考,或导航到代码菜单,并探索其菜单项和子菜单作为参考。
四、重构代码
你在 Android Studio 中开发的解决方案从设计到完成不会总是遵循一条直线。要成为一名高效的 Android 程序员,你需要在开发、调试和测试的过程中保持灵活性并重构代码。在前一章中,你学习了 Android Studio 如何生成代码;在这一章中,你将看到 Android Studio 如何重构你的代码。重构代码的最大风险是你可能会引入意想不到的错误。Android Studio 通过分析某些有风险的重构操作的后果来降低这些风险,然后激活查找工具窗口,在提交之前,您可以在其中预览您的更改(标记有任何错误或冲突)。
本章介绍的许多重构操作也可以在没有 Android Studio 重构工具的情况下执行。然而,您应该避免强力重构(例如,借助全局查找替换选项),因为 Android Studio 并不总是能够避免您在这些情况下引入错误。相比之下,如果 Android Studio 检测到你正在尝试重构操作,它会试图阻止你犯任何愚蠢的错误。例如,在“项目工具”窗口中,将 Java 源文件从一个包拖到另一个包将强制执行重构➤移动操作,该操作分析移动操作的结果,允许您预览更改,然后将整个项目中该类的任何导入语句优雅地更改为新的完全限定包名。
大多数重构操作都局限于一个方法或一个类,因此不太可能在项目中引入错误。有风险的重构操作是那些涉及两个或更多素材的操作。如果重构操作引入了编译错误,检查管理器将在编辑器中用红色标签标记受影响的素材。此时,您可以尝试修复它们,或者通过按 Ctrl+Z | Cmd+Z 来简单地撤消整个重构操作。如果重构操作成功且没有编译错误,但仍然涉及大量素材,您仍然应该运行您的测试来验证您没有引入任何运行时错误。第十一章涵盖了测试。
Tip
您应该将任何重要的重构更改作为单个 Git 提交,以便您可以在以后轻松地恢复该提交。第七章涵盖了 Git。
这一章主要关注最有用的重构操作。在我们开始讨论单独的重构操作之前,我们想指出 Android Studio 有一个非常方便的重构操作,叫做重构➤重构这个。选择这个选项会显示一个上下文菜单,如图 4-1 所示,它聚集了最有用的重构操作。这个操作的键盘快捷键是 Ctrl+Alt+Shift+T | Ctrl+T,在 PC 上你可以通过它方便记忆的首字母缩略词:CAST 来记住它。
图 4-1。
The Refactor This menu with the most useful refactoring operations
在开始学习本章中的例子之前,修改第三章中的Sandbox.java
文件,使其不扩展任何内容,既不包含方法也不包含成员,如下所示:
public class Sandbox {
}
重新命名
从项目工具窗口选择Sandbox
,然后导航到重构➤重命名或按 Shift+F6。产生的对话框允许您重命名您的类,并重命名注释、测试用例以及继承的类中出现的该名称。将Sandbox
重命名为 Playpen,点击重构按钮,如图 4-2 所示。您应该会在项目中看到重命名操作的结果。现在通过按 Ctrl+Z | Cmd+Z 撤消重命名操作。
图 4-2。
Rename Sandbox to Playpen
更改签名
更改签名操作使您能够更改方法的以下属性:可见性、名称、返回类型、参数和引发的异常。在Sandbox.java
中创建一个方法,如下面的代码片段所示:
public String``greetings
return "Hello " + message;
}
将光标放在单词greetings
(以粗体突出显示)上的任意位置,然后按 Ctrl+F6 | Cmd+F6,或者导航到重构➤更改签名。出现的对话框允许你修改方法的签名,如图 4-3 所示。
图 4-3。
The Change Signature dialog box
在参数选项卡中,点击String
信息项。将String
参数的名称从message
改为问候语,如图 4-3 所示。绿色加号和红色减号图标分别允许您向方法中添加参数或从中减去参数;您可以在列表中编辑它们的类型和名称。除了修改当前方法之外,您还可以通过重载方法单选按钮来选择委托。选择这个单选按钮将使您的原始方法不受影响,但是会用您定义的新签名生成另一个方法。在 Java 中,如果一组方法具有相同的名称,但是参数顺序和/或参数类型不同,则可以认为它们是重载的。但是,我们所做的更改并没有使这个方法适合重载。如果您愿意,可以在提交更改前通过单击预览按钮来预览更改。若要完成操作并关闭对话框,请单击“重构”按钮。
类型迁移
顾名思义,类型迁移允许您从一种 Java 类型迁移到另一种类型。让我们假设您创建了一个Person
类。在进一步的开发中,您发现Person
过于一般化,因此您创建了一个扩展Person
的Manager
类。如果您想将Person
的所有实例迁移到Manager
,您可以通过类型迁移轻松完成。
将光标放在greetings
方法的String
声明上(在下面的代码片段中以粗体突出显示),然后按 Ctrl+Shift+F6 | Cmd+Shift+F6,或者选择“重构➤类型迁移”。出现的对话框如图 4-4 所示。
图 4-4。
Type migration from string to date
public String greetings(``String
return "Hello " + greet;
}
将java.lang.String
改为 java.util.Date,如图 4-4 所示。从选择范围下拉列表中选择打开文件。与大多数重构操作一样,您可以通过单击预览按钮来预览您的更改。单击重构按钮。
移动
您可以通过以下三种方式之一移动源文件:
- 通过在项目工具窗口中将源文件从一个包拖到另一个包
- 通过选择源文件并从主菜单导航到重构➤移动
- 通过在项目工具窗口中选择文件并按下 F6
右键单击(在 Mac 上按住 Ctrl 键单击)这个com.apress.gerber.helloworld
包,然后选择“新建➤包”。将包命名为 refactor。从项目工具窗口中,将Sandbox
类拖放到refactor
包中,当出现如图 4-5 所示的对话框时,点击 OK。您在“项目工具”窗口中执行的任何拖放操作都会自动强制执行重构➤移动操作,这允许您将类从一个包安全地移动到另一个包。
图 4-5。
The Move dialog box, resulting from drag-and-drop
除了移动类,您还可以移动成员。在您的Sandbox
类中,定义一个新成员,如下所示:
public static final String HELLO = "Hello Android Studio";
将光标放在这行代码上,然后按 F6。出现的对话框允许你将成员从一个类移动到另一个类,如图 4-6 所示。单击“取消”按钮取消此操作。
图 4-6。
The Move Members dialog box
复制
“复制”与“移动”类似,可通过按键盘快捷键 F5 或从主菜单中选择“重构➤复制”来访问。在项目工具窗口中,选择refactor
包中的Sandbox
类,然后按 F5。在目的包下拉菜单中选择com.apress.gerber.helloworld
包,点击确定,如图 4-7 所示。像我们在这里所做的那样不加选择地复制 Java 源文件并不是一个好主意,因为解析是不明确的,因此容易产生潜在的错误。
图 4-7。
The Copy Class dialog box
安全删除
让我们删除我们创建的复制类。您可以在 Android Studio 中删除文件和资源,方法是在项目工具窗口中选择它们,然后按下 delete 键。点击refactor
包中的Sandbox
文件,按 Delete 键。出现的对话框允许您通过选中安全删除复选框来使用安全删除选项。使用安全删除的好处是,我们可以在执行删除之前搜索素材上任何可能被破坏的依赖关系,如图 4-8 所示。如果在您的项目中发现此素材的任何依赖项,您将可以选择查看它们,或者通过单击“仍然删除”来强制执行删除操作。
图 4-8。
The Safe Delete dialog box
提取
提取不只是一个操作,而是几个操作。本节涵盖了一些更重要的提取操作:提取变量、提取常数、提取字段、提取参数和提取方法。在Sandbox
类中,让我们删除所有成员和方法,从头开始:
public class Sandbox {
}
提取变量
在您的Sandbox.java
类中,定义一个方法,如下所示:
private String saySomething(){
return "``Something
}
将光标放在硬编码的Something
值(以粗体突出显示)上的任意位置,并选择重构➤提取➤变量,或者按 Ctrl+Alt+V | Cmd+Alt+V,然后在不选中声明最终值复选框的情况下按 Enter。Android Studio 提取一个局部变量,按照硬编码的String
命名。您应该会得到这样的结果:
private String saySomething(){
String something =
"Something";
return something;
}
提取常数
当你在 Android 中开发应用时,你会发现自己使用了大量的Strings
作为键——例如,在Maps
和Bundles
中。所以提取常量会节省你很多时间。
定义一个方法,如下面的代码片段所示。将光标放在name_key
字符串上的任意位置,然后按 Ctrl+Alt+C | Cmd+Alt+C。出现的对话框应该如图 4-9 所示。在这里,Android Studio 为名字提供了几个建议。按照惯例,Java 中的常量都是大写的。选择NAME_KEY
并按下回车键。
图 4-9。
Extract Constant NAME_KEY Note
您将需要import android.os.Bundle
来创建没有编译时错误的 proceding 方法。
private void addName(String name, Bundle bundle ){
bundle.putString("``name_key
}
您最终应该得到一个名为NAME_KEY
的常数,它应该这样定义:
public static final String NAME_KEY = "name_key";
提取字段
提取字段将局部变量转换为类的字段(也称为成员)。
Note
为了创建没有编译时错误的 proceding 方法,您需要导入java.util.Date
。
在您的Sandbox
类中定义一个方法:
private Date getDate(){
return new``Date
}
将光标放在Date
(粗体突出显示)的任意位置,按 Ctrl+Alt+F | Cmd+Alt+F。您将看到如图 4-10 所示的对话框。在 Android 中,命名约定是在字段(也称为成员)前加一个 m。您还会注意到一个下拉菜单,允许您在当前方法、字段声明或构造函数中初始化字段。选择字段声明并按回车键。
图 4-10。
The Extract Field dialog box
您应该会得到这样的结果:
private final Date mDate = new Date();
...
private Date getDate(){
return mDate;
}
删除final
关键字,使声明行看起来像下面的代码片段:
private Date mDate = new Date();
提取参数
Extract Parameter 允许您提取一个变量,并将其作为封闭方法的参数。在您的Sandbox
类中定义一个方法:
private void setDate(){
mDate = new``Date()
}
将光标放在Date()
上的任意位置(以粗体突出显示),按 Ctrl+Alt+P | Cmd+Alt+P,然后按 Enter。结果方法应该类似于下面的代码片段:
private void setDate(Date date){
mDate = date;
}
提取方法
“提取方法”允许您选择一行或多行连续的代码,并将它们放在单独的方法中。你想这么做有两个原因。第一个原因是你有一个太复杂的方法。将一个算法分成大约 10-20 行的离散块,比一个有 100 行代码的方法更容易阅读,也更不容易出错。
重复代码块几乎从来都不是一个好主意,所以如果您发现重复的代码块,最好提取一个方法并调用该方法来代替重复的代码块。通过提取一个方法并在您之前使用重复代码块的地方调用它,您可以在一个地方维护您的方法,并且如果您需要修改它,您只需要修改它一次。在你的Sandbox
类中重新创建以下两个方法,如清单 4-1 所示。随意复制粘贴。
Listing 4-1. Exract Method Code
private String methodHello (){
String greet = "Hello";
StringBuilder stringBuilder = new StringBuilder();
for(int nC = 0; nC < 10; nC++){
stringBuilder.append(greet + nC);
}
return stringBuilder.toString();
}
private String methodGoodbye (){
String greet = "Goodbye";
StringBuilder stringBuilder = new StringBuilder();
for(int nC = 0; nC < 10; nC++){
stringBuilder.append(greet + nC);
}
return stringBuilder.toString();
}
正如我们已经提到的,任何时候你发现自己重复代码块或者复制粘贴代码块,你应该考虑使用 Extract 方法。选择清单 4-1 中所有粗体突出显示的行。现在按 Ctrl+Alt+M | Cmd+Alt+M 提取方法。您将看到一个显示方法签名的对话框。将该方法重命名为 getGreet,如图 4-11 所示,点击确定。
图 4-11。
The Extract Method dialog box
Android Studio 扫描您的文件,发现您有另一个完全相同的代码块实例。点击【是】接受流程复制对话框中的建议,如图 4-12 所示。
图 4-12。
The Process Duplicates dialog box
您应该得到类似清单 4-2 的结果。结果方法更容易维护,因为它保存在一个地方。
Listing 4-2. Code Resulting from Extract Method Operation
private String methodHello (){
String greet = "Hello";
return getGreet(greet);
}
private String methodGoodbye (){
String greet = "Goodbye";
return getGreet(greet);
}
private String getGreet (String greet){
StringBuilder stringBuilder = new StringBuilder();
for(int nC = 0; nC < 10; nC++){
stringBuilder.append(greet + nC);
}
return stringBuilder.toString();
}
高级重构
本章剩余部分介绍的重构操作是高级的。如果你只是对快速使用 Android Studio 感兴趣,你已经有足够的知识来有效地使用重构操作,你可以跳过这一节。然而,如果你很好地理解了 Java,并且想要深入一些更高级的重构操作,请继续阅读。
通过删除Sandbox.java
中的所有方法和成员,从头开始:
public class Sandbox {
}
在项目工具窗口中右键单击(在 Mac 上按住 Ctrl 键单击)该com.apress.gerber.helloworld
包,然后选择“新建➤ Java 类”。把你的班级命名为迷你箱。更改Minibox
的定义,使其继承自Sandbox
,并拥有一个名为mShovel
的成员,如下所示:
public class Minibox extends Sandbox {
private String mShovel;
}
向下推动构件,向上拉动构件
向下推成员和向上拉成员与继承一起使用。注意,我们已经在Minibox
类中定义了mShovel
成员。假设我们后来决定mShovel
可能对其他扩展Sandbox
的类有用。为此,打开Minibox
类并选择 Refactor ➤向上拉成员。出现的对话框如图 4-13 所示。
图 4-13。
The Pull Members Up dialog box
由于Sandbox
是Minibox
的超类,默认情况下mShovel
成员被选中,下拉成员组合框被设置为com.apress.gerber.helloworld.Sandbox
类。单击重构。如果您现在检查Sandbox
和Minibox
,您会注意到mShovel
成员属于Sandbox
,不再出现在Minibox
中。一般来说,如果您认为某个成员可能对其他扩展类有用,您应该将这些成员提升到层次结构中。要向下推动成员,可以遵循类似的步骤。
用委派替换继承
右键单击(在 Mac 上按住 Ctrl 键单击)这个com.apress.gerber.helloword
包,然后选择“新建➤ Java 类”。将您的类命名为 Patio,并将其扩展为Sandbox
:
public class Patio extends Sandbox {
}
经过进一步分析,我们决定Patio
不是一个Sandbox
,而是有一个Sandbox
。要更改这种关系,导航到重构➤用委托替换继承。在弹出的对话框中,点击为委托组件生成 Getter 复选框,如图 4-14 所示。
图 4-14。
The Replace Inheritance with Delegation dialog box
您的Patio
类现在应该有一个Sandbox
成员,如下面的代码片段所示:
public class Patio {
private final Sandbox mSandbox = new Sandbox();
public Sandbox getSandbox() {
return mSandbox;
}
}
封装字段
封装是一种面向对象的策略,它通过将类成员的访问级别设为私有来隐藏类成员,然后通过公共 getter/setter 方法向这些成员提供公共接口。重构➤封装字段类似于代码➤生成➤ Getter 和 Setter,尽管当您选择重构➤封装字段时有更多的选择。打开您的Sandbox
类并定义一个名为mChildren
的新成员,在下一段代码中以粗体突出显示。从主菜单中,选择重构➤封装字段。
public class Sandbox {
private String mShovel;
private int mChildren;
}
出现的对话框允许您准确选择字段的封装方式以及它们应该具有的访问级别。一个真正封装的字段将具有公共访问器(getter)和赋值器(setter)方法的私有可见性。点击 Refactor 按钮,如图 4-15 所示,注意 Android Studio 已经在我们的Sandbox.java
类中为我们生成了 getters 和 setters。
图 4-15。
The Encapsulate Fields dialog box
包装方法返回值
当您需要返回一个对象而不是一个原语时,包装一个返回值可能是有用的(尽管在其他情况下您可能希望包装一个返回值)。将光标放在getChildren()
方法上,导航到重构➤包装方法返回值。选中使用现有类复选框,键入 java.lang.Integer 作为名称,键入 value 作为包装字段,如图 4-16 所示。现在单击 Refactor,注意您的getChildren()
方法返回了一个Integer
对象,而不是一个原语int
。
图 4-16。
The Wrap Return Value dialog box
用工厂方法替换构造函数
将光标放在Sandbox
类定义的括号内。按 Alt+Insert | Cmd+N 并选择构造函数以生成新的构造函数。选择两个成员,如图 4-17 所示,点击确定。
图 4-17。
The Choose Fields to Initialize by Constructor dialog box
将光标放在新定义的构造函数中的任意位置,如下面的代码片段所示,然后导航到重构➤用工厂方法替换构造函数。出现的对话框如图 4-18 所示。单击“重构”以生成工厂方法。
图 4-18。
The Replace Constructor with Factory Method dialog box
public Sandbox(String shovel, int children) {
mShovel = shovel;
mChildren = children;
}
注意,构造函数现在是私有的,一个新的静态方法返回了一个Sandbox
类的实例,如下面的代码片段所示。如果您正在创建单例,此操作特别有用。
public static Sandbox createSandbox(String shovel, int children) {
return new Sandbox(shovel, children);
}
将匿名转换为内部
在Sandbox
类的构造函数中,添加下面一行:
new Thread(new Runnable()).start();
将光标放在Runnable()
上,按 Alt+Enter 调用代码完成操作。然后选择实现方法。选择run
方法并点击确定。您的代码应该类似于下面的代码片段:
new Thread(new Runnable() {
@Override
public void run() {
//do something
}
}).start();
将光标放在Runnable()
上,导航到重构➤将匿名转换为内部。Android Studio 给你建议MyRunnable
作为类名,如图 4-19 。取消选中“使类成为静态”复选框,然后单击“确定”。注意,现在在Sandbox.java
中有了一个名为MyRunnable
的私有内部类,它实现了Runnable
接口。这个例子没做多少;但是,在委派Views
的行为时,您可能有机会使用此操作。
图 4-19。
The Convert Anonymous to Inner dialog box
摘要
本章讨论了 Android Studio 中许多可用的重构操作。重构代码是任何编程项目的必要组成部分,Android Studio 中的重构工具就是其中的佼佼者。Android Studio 通过分析结果来降低执行某些重构操作的风险,并允许您在提交操作之前在 Find tool 窗口中预览结果。最重要的重构操作可从“重构➤重构此对话框”中获得,该对话框通过使用键盘快捷键 Ctrl+Alt+Shift+T | Ctrl+T 来调用
五、提醒 Lab:第一部分
到目前为止,您已经熟悉了创建新项目、编程和重构的基础知识。是时候创建一个 Android 应用了,也就是所谓的 app。本章介绍四个实验项目中的第一个。这些实验旨在让您熟悉在开发应用的背景下使用 Android Studio。在这个项目中,您将开发一个应用来管理您想要记住的项目列表。核心功能将允许您创建和删除提醒,并将某些提醒标记为重要。提醒文本左侧的橙色标签会强调一个重要项目。该应用将包含一个动作栏菜单,上下文菜单,一个持久化的本地数据库,以及支持多重选择的设备上的多重选择。
图 5-1 展示了在仿真器上运行的完整应用。这个例子向您介绍了 Android 的基础知识,您还将学习如何通过使用内置的 SQLite 数据库来持久化数据。如果有些题目不熟悉也不用担心;后面的章节将更详细地介绍这些主题。
图 5-1。
The completed app interface Note
我们邀请您使用 Git 克隆这个项目,以便跟进,尽管您将从头开始使用它自己的 Git 库重新创建这个项目。如果你的电脑上没有安装 Git,参见第七章。在 Windows 中打开一个 Git-bash 会话(或者在 Mac 或 Linux 中打开一个终端)并导航到C:\androidBook\reference\
(如果您没有参考目录,请创建一个。在 Mac 上,导航到/your-labs-parent-dir/reference/)并发出以下 git 命令:git clone https://bitbucket.org/csgerber/reminders.git
Reminders。
要操作提醒应用,您可以使用操作栏的溢出菜单。点击溢出按钮,它看起来像菜单栏右侧的三个垂直点,打开一个有两个选项的菜单,如图 5-2 所示:新提醒和退出。点击新建提醒打开如图 5-3 所示的对话框。在对话框中,您可以为新提醒添加文本,然后点击提交将其添加到列表中。轻按“退出”即可退出应用。
图 5-3。
New Reminder dialog box
图 5-2。
App interface with overflow menu activated
点击列表中的任一提醒会打开一个带有两个选项的上下文菜单,如图 5-4 所示:编辑提醒和删除提醒。点击上下文菜单中的编辑提醒打开编辑提醒弹出对话框,如图 5-5 所示,在此可以更改提醒的文本。点击上下文菜单中的删除提醒可从列表中删除提醒。
图 5-5。
Edit Reminder dialog box
图 5-4。
Context menu
开始一个新项目
按照第一章中的说明,使用新建项目向导在 Android Studio 中启动一个新项目。输入提醒作为应用名称,设置公司域为 gerber.apress.com
,选择空白活动模板。将该项目保存在路径C:\androidBook\Reminders
下。为了与我们的示例保持一致,最好将您的所有 Lab 项目保存在一个公共文件夹中,例如C:\androidBook
(或者对于 Mac/Linux 使用∼/androidBook
)。在向导的下一页,选择 Phone and Tablet,将最低 SDK 设置为 API 8: Android 2.2 (Froyo)。通过将你的最小 API 级别设置为 8,你的应用可以被超过 99%的 Android 市场使用。单击 Next 按钮,从可用模板中选择空白活动,然后再次单击 Next。将活动名称设置为RemindersActivity
,然后点击完成,如图 5-6 所示。
图 5-6。
Entering an activity name
Android Studio 在设计模式下显示activity_reminders.xml
。activity_reminders.xml
文件是你的主活动的布局,如图 5-7 所示。正如在第一章中所讨论的,项目应该在模拟器或者设备上运行。请随意连接您的设备或启动您的仿真器,并运行该项目进行测试。
图 5-7。
Design mode for activity_reminders
初始化 Git 储存库
创建新项目后的第一步应该是使用版本控制来管理源代码。这本书的所有实验都使用 Git,这是一个流行的版本控制系统,可以与 Android Studio 无缝协作,并且可以在网上免费获得。第七章更彻底地探讨了 Git 和版本控制。
如果您的计算机上尚未安装 Git,请参考第七章中标题为安装 Git 的章节。从主菜单中选择 VCS ➤导入到版本控制➤创建 Git 存储库。(在 Apple OS 中,选择 VCS ➤ VCS Operations ➤创建 Git 存储库。)图 5-8 和 5-9 展示了这一流程。
图 5-9。
Selecting the root directory for the Git repository
图 5-8。
Creating the Git repository
当提示为 Git init 选择目录时,确保 Git 项目将在根项目目录中初始化(在本例中也称为Reminders
)。单击确定。
您会注意到位于项目工具窗口中的大多数文件都变成了棕色,这意味着它们正在被 Git 跟踪,但是还没有被添加到 Git 存储库中,也没有被计划添加。一旦你的项目在 Git 的控制之下,Android Studio 就使用一种颜色方案来指示文件在创建、修改或删除时的状态。随着我们的进展,我们会更详细地解释这个着色方案,不过你可以在这里更详细地研究这个主题:jetbrains.com/idea/help/file-status-highlights.html.
单击位于底部空白处的“更改工具”按钮,切换打开“更改工具”窗口,并展开标记为“未版本化的文件”的叶。这将显示所有被跟踪的文件。要添加它们,请选择未版本化文件叶,然后按 Ctrl+Alt+A | Cmd+Alt+A,或者右键单击未版本化文件叶,然后选择“Git ➤添加”。棕色文件应该已经变成绿色,这意味着它们已经在 Git 中暂存,现在可以提交了。
按 Ctrl+K | Cmd+K 调用提交更改对话框。提交文件是将项目变更记录到 Git 版本控制系统的过程。如图 5-10 所示,作者下拉菜单用于覆盖当前默认提交者。您应该将 Author 字段留空,Android Studio 将简单地使用您在 Git 安装期间最初设置的默认值。取消选择“提交前”部分中的所有复选框选项。将以下消息放入提交消息字段:使用新建项目向导进行初始提交。单击提交按钮,并从下拉项目中再次选择提交。
图 5-10。
Committing changes to Git
默认情况下,项目工具窗口应处于打开状态。“项目工具”窗口以不同的方式组织您的项目,这取决于在窗口顶部的“模式”下拉菜单中选择的视图。默认情况下,下拉菜单设置为 Android view,它根据文件的用途来组织文件,与文件在计算机操作系统上的组织方式无关。在浏览项目工具窗口时,您会注意到 app 文件夹下有三个文件夹:manifests
、java
和res
。在manifests
文件夹中可以找到您的 Android 清单文件。在java
文件夹中可以找到你的 Java 源文件。res
文件夹保存了你所有的 Android 资源文件。位于res
目录下的资源可能是 XML 文件、图像、声音和其他有助于定义应用外观和 UI 体验的资源。一旦你有机会探索 Android 视图,我们建议切换到更直观的项目视图,因为它直接映射到您计算机上的文件结构。
Note
如果您使用过其他 ide 或旧的 Android Studio 测试版本,您会注意到自从 Android Studio 发布以来,在项目工具窗口中引入了 Android 和包视图。
构建用户界面
默认情况下,Android Studio 在编辑器的新选项卡中打开与主活动相关联的 XML 布局文件,并将其模式设置为 Design,因此可视化设计器通常是您在新项目中看到的第一个东西。可视化设计器允许您编辑应用的可视化布局。屏幕中间是预览窗格。预览窗格显示 Android 设备的可视化表示,同时呈现您当前编辑的布局的结果。这种表示可以通过使用屏幕顶部的预览布局控件来控制。这些控件可以调整预览,并可用于选择不同(或多种)风格的 Android 设备,从智能手机到平板电脑或可穿戴设备。您还可以更改与布局描述相关联的主题。在屏幕的左侧,您会发现控制面板。它包含各种控件和小部件,可以拖放到舞台上,舞台是设备的可视化表示。ide 的右侧包含一个组件树,显示布局中描述的组件的层次结构。布局使用 XML。当您在可视设计器中进行更改时,这些更改会在 XML 中更新。您可以单击“设计”和“文本”选项卡,在可视和文本编辑模式之间切换。图 5-11 指出了视觉设计者的几个关键领域。
图 5-11。
The Visual Designer layout
使用可视化设计器
让我们从创建一个提醒列表开始。单击舞台上的 Hello World TextView
控件,然后按 Delete 键删除它。在调色板中找到ListView
控件,并将其拖到舞台上。拖动时,IDE 将显示各种度量和对齐参考线,以帮助您定位控件,当您拖动控件靠近边缘时,这些参考线往往会与边缘对齐。放下ListView
,使其与屏幕顶部对齐。您可以将它放置在左上角或中上方。定位后,在编辑器的右下方找到 Properties 视图。将id
属性设置为reminders_list_view
。id
属性是一个可以赋予控件的名称,允许您在 Java 代码中以编程方式引用它们;这就是我们以后修改 Java 源代码时引用ListView
的方式。在属性窗口中更改layout:width
属性,并将其设置为match_parent
。这将扩展控件,使其占据与其所在的父控件一样多的空间。你将在第八章中了解更多关于设计布局的细节。现在,你的布局应该如图 5-12 所示。
图 5-12。
The activity_reminders layout with a ListView
在 Android 中,一个活动定义了控制用户与应用交互的逻辑。当第一次学习 Android 时,将一个活动想象成应用中的一个屏幕会有所帮助,尽管活动可能比这更复杂。这些活动通常会扩大一个布局,该布局定义了事物在屏幕上出现的位置。布局文件被定义为 XML,但可以使用可视化设计器进行可视化编辑,如前所述。
编辑布局的原始 XML
单击底部的文本选项卡,从可视编辑切换到文本编辑。这将显示布局的原始 XML 视图,以及右侧的实时预览。对 XML 所做的更改会立即反映在预览窗格中。通过在显示android:layout_height="match_parent"
的行下面插入android:background="#181818"
,将相对布局的背景颜色更改为深灰色。颜色以十六进制值表示。关于十六进制颜色值的更多信息,参见第九章。请注意,现在有一个深灰色样本出现在您插入的设置根视图组背景颜色的行旁边的 gutter 中。如果您切换回设计模式,您会发现整个布局现在是深灰色的。
直接在 XML 布局文件中硬编码颜色值不是最好的方法。更好的选择是在 values resource 文件夹下定义一个colors.xml
文件,并在那里定义您的颜色。我们将值外部化到 XML 文件(如 colors.xml)的原因是,这些资源保存在一个地方并可以在一个地方编辑,在整个项目中可以很容易地引用它们。
选择十六进制值#181818
并使用 Ctrl+X | Cmd+X 或选择编辑➤剪切将其剪切到剪贴板。在其位置键入@color/dark_grey。这个值使用特殊的语法来引用名为dark_grey
的 Android 颜色值。这个值应该在一个名为colors.xml
的 Android 资源文件中定义,但是因为这个文件在你的项目中还不存在,Android Studio 用红色突出显示了这个错误。按 Alt+Enter,系统会提示您改正错误的选项。选择第二个选项,创建颜色值资源dark_grey
,然后将该值粘贴到出现的下一个对话框的资源值:字段中,并单击确定。
新的颜色值资源对话框将创建 Android 资源文件colors.xml
并用十六进制值填充它。单击“确定”,然后在“将文件添加到 Git”对话框中单击“确定”,将此新文件添加到版本控制中,并确保选中“记住,不要再询问”复选框,这样您就不会再受到此消息的困扰。图 5-13 展示了这一流程。
图 5-13。
Extracting the hard-coded color value as a resource value
预览模式中的ListView
包含的行布局与我们选择的背景颜色没有足够的对比度。要更改这些项目的显示方式,您需要在单独的布局文件中为该行定义一个布局。右键单击res
文件夹下的layout
文件夹,选择新建➤布局资源文件。在“新建资源文件”对话框中输入 reminders_row。使用LinearLayout
作为根视图组,保留其余的默认设置,如图 5-14 所示。
图 5-14。
New Resource File dialog box
现在,您将为单个列表项行创建布局。LinearLayout
根视图组是布局中最外面的元素。使用预览窗格顶部工具栏中的控件将其方向设置为vertical
。使用此控件时要小心,因为水平线表示垂直方向,反之亦然。图 5-15 突出显示了改变方向按钮。
图 5-15。
Change Orientation button
在预览窗格的右下角找到属性视图。找到layout:height
属性并将其设置为50dp
。此属性控制控件的高度,dp 后缀是指与密度无关的像素度量。这是 Android 使用的一个指标,允许布局适当缩放,而不管呈现它们的屏幕密度如何。您可以单击此视图中的任何属性,并开始键入内容以增量方式搜索属性,然后按向上或向下箭头继续搜索。
将一个水平LinearLayout
拖放到垂直LinearLayout
内。将一个CustomView
控件拖放到水平LinearLayout
中,并将其 class 属性设置为android.view.View
,以创建一个通用的空视图,并赋予它一个row_tab
的id
属性。在撰写本文时,Android Studio 中有一个限制,不允许您从面板中拖动通用视图。一旦你点击CustomView
,你会得到一个有不同选项的对话框,没有一个选项包含通用视图类。从对话框中选择任意一个类,并将其放置在布局中。使用 properties 窗格右侧的 properties 窗口找到刚才放置的视图的 class 属性,并将其更改为android.view.View
以解决此限制。参考清单 5-1 来查看这是如何完成的。
您将使用此通用视图选项卡将某些提醒标记为重要。在编辑模式仍然设置为文本的情况下,将自定义视图的layout:width
属性更改为10dp
,将其layout:height
属性设置为match_parent
。在这里使用match_parent
值将使这个View
控件与其父容器一样高。切换到设计模式,在组件树的水平LinearLayout
中拖放一个Large Text
控件,并将其width
和height
属性设置为match_parent
。验证大文本组件是否位于自定义视图控件的右侧。在组件树中,标记为 textView 的组件应该嵌套在 LinearLayout (horizontal)组件中,并位于 View 组件之下。如果“文本视图”出现在“视图”上方,请用鼠标向下拖动它,使它吸附到第二个(也是最后一个)位置。给你的 TextView 控件一个id
值row_text
,并将其textSize
属性设置为18sp
。sp 后缀指的是与比例无关的像素测量,其表现类似于dp
,但也尊重用户的文本大小设置,例如,如果用户视力不好,并希望其手机上的文本显示较大,sp
会尊重此设置,而dp
则不会。因此,对textSize
使用sp
总是一个好主意。你将在第八章中了解更多关于屏幕尺寸的信息。
最后,将 TextView 控件的text
属性设置为Reminder Text
。切换到文本模式,对 XML 进行额外的修改,使您的代码类似于清单 5-1 。
Listing 5-1. The reminders_row Layout XML Code
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="``http://schemas.android.com/apk/res/android
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="vertical">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="48dp">
<view
android:layout_width="10dp"
android:layout_height="match_parent"
class="android.view.View"
android:id="@+id/row_tab" />
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:textAppearance="?
android:attr/textAppearanceLarge"
android:text="Reminder Text"
android:id="@+id/row_text"
android:textSize="18sp" />
</LinearLayout>
</LinearLayout>
现在,您将创建一些自定义颜色。切换到设计模式。在组件树中选择根 LinearLayout (vertical)。将其 android:background 属性设置为@color/dark_grey
以重用我们之前定义的颜色。在组件树中选择 row_tab 组件,并将其android:background
属性设置为@color/green
。选择 row_text 组件,并将其android:textColor
属性设置为@color/white
。与之前一样,这些颜色没有在colors.xml
文件中定义,您需要使用与之前相同的过程来定义它们。切换到文本模式。重复按 F2 键在这两个附加错误之间来回跳转,然后按 Alt+Enter 键调出 IntelliSense 建议。在两种情况下选择第二个建议,并在弹出的对话框中填入值#ffffff
以固定白色,填入值#003300
以固定绿色。在使用建议对话框修复这些错误后,您可以按住 Ctrl 键并左键单击这些颜色中的任何一种,这将把您带到colors.xml
文件,看起来应该如清单 5-2 所示。
Listing 5-2. The colors.xml File
<resources>
<color name="dark_grey">#181818</color>
<color name="white">#ffffff</color>
<color name="green">#003300</color>
</resources>
返回到activity_reminders.xml
布局文件。现在你可以将新的reminders_row
布局连接到这个布局中的ListView
。切换到文本模式,给ListView
元素添加如下属性:tools:listitem="@layout/reminders_row"
,如图 5-16 所示。
图 5-16。
The preview pane is now rendering a custom ListView layout
添加此属性不会更改布局运行时的呈现方式;它只是改变了预览窗格对列表视图中每个项目的使用。要使用新的布局,您必须使用 Java 代码来扩展它,我们将在后续步骤中向您展示如何操作。
添加视觉增强
您已经完成了 ListView 行的自定义布局,但是您不应该就此止步。添加一些视觉增强会让你的应用与众不同。看看文本是如何在屏幕上呈现的。细心的人会发现它稍微偏离了中心,碰到了左边的绿色标签。打开reminders_row
布局进行一些小的调整。您希望文本向行的垂直中心移动,并提供一些填充,以便从侧边提供一些视觉分离。用清单 5-3 中的代码替换您的TextView
元素。
Listing 5-3. TextView Additional Attributes
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="Reminder Text"
android:id="@+id/row_text"
android:textColor="@color/white"
android:textSize="18sp"
android:gravity="center_vertical"
android:padding="10dp"
android:ellipsize="end"
android:maxLines="1"
/>
附加的ellipsize
属性将截断太长的文本,使其不适合末尾带有省略号的行,而maxLines
属性将每行的行数限制为 1。最后,从清单 5-4 中添加两个通用视图对象,在内部LinearLayout
之后,外部LinearLayout
的结束标记之前,在该行下面创建一个水平标尺。外LinearLayout
设置为高度50dp
,内LinearLayout
设置为高度48dp
。两个通用视图对象将占据布局内剩余的垂直 2dp,从而创建一个斜边。这显示在清单 5-4 中。
Listing 5-4. Extra Generic Views for beveled edge
</LinearLayout>
<view
class="android.view.View"
android:layout_width="fill_parent"
android:layout_height="1dp"
android:background="#000"/>
<view
class="android.view.View"
android:layout_width="fill_parent"
android:layout_height="1dp"
android:background="#333"/>
</LinearLayout>
向 ListView 添加项目
现在,您将对使用您刚刚修改的布局的活动进行更改。打开项目工具窗口,在您的java
源文件夹下找到RemindersActivity
文件。它将位于com.apress.gerber.reminders
包下。在这个文件中找到onCreate()
方法。它应该是您的类中定义的第一个方法。声明一个名为 mListView 的 ListView 成员,并将onCreate()
方法修改成清单 5-5 中的代码。您将需要解析导入 ListView 和 ArrayAdapter。
Listing 5-5. Add List Items to the ListView
public class RemindersActivity extends ActionBarActivity {
private ListView mListView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_reminders);
mListView = (ListView) findViewById(R.id.reminders_list_view);
//The arrayAdatper is the controller in our
//model-view-controller relationship. (controller)
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(
//context
this,
//layout (view)
R.layout.reminders_row,
//row (view)
R.id.row_text,
//data (model) with bogus data to test our listview
new String[]{"first record", "second record", "third record"});
mListView.setAdapter(arrayAdapter);
}
//Remainder of the class listing omitted for brevity
}
这段代码通过使用您之前定义的id
属性来查找ListView
,并删除默认的列表分隔线,以便我们之前创建的定制斜面分隔线能够正确呈现。该代码还创建了一个带有几个示例列表项的适配器。Adapter
是一个特殊的 Java 类,被定义为 Android SDK 的一部分,在 SQLite 数据库(模型)、ListView(视图)和适配器(控制器)之间的模型-视图-控制器关系中充当控制器。适配器将模型绑定到视图,并处理更新和刷新。Adapter 是 ArrayAdapter 的超类,它将数组的元素绑定到视图。在我们的例子中,这个视图是一个 ListView。ArrayAdapter
在其三参数构造函数中接受三个参数。第一个参数是由当前活动表示的一个Context
对象。适配器还需要知道应该使用哪个布局和布局中的哪个或哪些字段来显示行数据。为了满足这个需求,您传递布局和布局中的TextView
项的 id。最后一个参数是用于列表中每一项的字符串数组。如果此时运行项目,您将会看到列表视图中显示的ArrayAdapter
构造函数中给出的值,如图 5-17 所示。
图 5-17。
ListView example
按 Ctrl+K | Cmd+K 提交对 Git 的更改,并使用带有自定义颜色的 Adds ListView 作为提交消息。当您完成一个项目时,最好对 Git 执行增量提交,同时使用提交消息来描述每次提交添加/删除/更改的特性。保持这种习惯使得识别单个提交和为将来的合作者和用户构建发布说明变得容易。
设置操作栏溢出菜单
Android 使用一种常见的视觉元素,称为动作栏。操作栏是许多应用定位导航和其他允许用户执行重要任务的选项的地方。此时运行应用时,您可能会注意到一个看起来像三个垂直点的菜单图标。这些点被称为溢出菜单。单击溢出菜单图标会产生一个菜单,其中有一个名为settings
的菜单项。该菜单项作为新建项目向导模板的一部分放在那里,本质上是一个不执行任何操作的占位符。RemindersActivity
加载menu_reminders.xml
文件,该文件位于res/menu
文件夹下。对这个文件进行修改,向活动添加新的菜单项,如清单 5-6 所示。
Listing 5-6. New Menu Items
<menu xmlns:android="``http://schemas.android.com/apk/res/android
xmlns:app="``http://schemas.android.com/apk/res-auto
xmlns:tools="``http://schemas.android.com/tools
tools:context="com.apress.gerber.reminders.app.RemindersActivity" >
<item android:id="@+id/action_new"
android:title="new Reminder"
android:orderInCategory="100"
app:showAsAction="never" />
<item android:id="@+id/action_exit"
android:title="exit"
android:orderInCategory="200"
app:showAsAction="never" />
</menu>
在前面的代码清单中,title
属性对应于菜单项中显示的文本。由于我们已经对这些属性进行了硬编码,Android Studio 会将这些值标记为警告。按 F2 在这些警告之间跳转,按 Alt+Enter 调出 IntelliSense 建议。您只需按 Enter 键接受第一个建议,为新的字符串资源键入一个名称,当对话框弹出时,再次按 Enter 键接受命名的资源。使用new_reminder
作为第一个项目的名称,使用exit
作为第二个项目的名称。
打开RemindersActivity
并用清单 5-7 中的文本替换onOptionsItemSelected()
方法。您需要解决日志类的导入问题。当你点击应用中的一个菜单项时,运行时会调用这个方法,传入一个被点击的MenuItem
的引用。switch
语句接受MenuItem
的itemId
,并根据点击的项目执行日志语句或终止活动。这个例子使用了将文本写入 Android 调试日志的Log.d()
方法。如果您的应用包含多个活动,并且这些活动是在当前活动之前查看的,那么调用finish()
将简单地从 backstack 中弹出当前活动,控制权将传递给下一个底层活动。因为 RemindersActivity 是这个应用中唯一的活动,finish()
方法从 backstack 中弹出唯一的活动,并导致您的应用终止。
Listing 5-7. onOptionsItemSelected( ) Method Definition
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_new:
//create new Reminder
Log.d(getLocalClassName(),"create new Reminder");
return true;
case R.id.action_exit:
finish();
return true;
default:
return false;
}
}
运行应用并测试新的菜单选项。轻按新的提醒菜单选项,并观看 Android 日志以查看消息出现。在仿真器或设备上运行应用时,将会打开 Android DDMS(Dalvik 调试监控服务)窗口,您需要选择日志级别下的调试选项来查看调试日志。运行您的应用并与菜单项交互。点击新的提醒菜单项时,请注意 Android DDMS 窗口中的日志。最后,按 Ctrl+K | Cmd+K,使用添加新的提醒和退出菜单选项作为提交消息,将代码提交给 Git。
持续提醒
因为提醒应用需要维护一个提醒列表,所以你需要一个持久性策略。Android SDK 和运行时提供了一个名为 SQLite 的嵌入式数据库引擎,该引擎旨在在内存受限的环境中运行,非常适合移动设备。本节介绍 SQLite 数据库,并探讨如何维护提醒列表。我们的策略将包括一个数据模型、一个数据库代理类和一个CursorAdapter
。该模型将保存从数据库读取和写入数据库的数据。代理将是一个适配器类,它将把来自应用的简单调用转换成对 SQLite 数据库的 API 调用。最后,CursorAdapter
将扩展一个标准的 Android 类,以抽象的方式处理数据访问。
数据模型
让我们从创建数据模型开始。右键单击 com.apress.gerber.reminders 包并选择 New ➤ Java Class。命名您的课堂提醒,然后按回车键。用清单 5-8 中的代码装饰你的类。这个类是一个简单的 POJO (Plain Old Java Object ),它定义了一些实例变量和相应的 getter 和 setter 方法。Reminder
类包括一个整数 ID、一个字符串值和一个数字重要性值。ID 是用于识别每个提醒的唯一号码。字符串值保存提醒的文本。重要性值是一个数字指示器,将单个提醒标记为重要(1 =重要,0 =不重要)。我们在这里使用了int
而不是boolean
,因为 SQLite 数据库没有boolean
数据类型。
Listing 5-8. Reminder Class Definition
public class Reminder {
private int mId;
private String mContent;
private int mImportant;
public Reminder(int id, String content, int important) {
mId = id;
mImportant = important;
mContent = content;
}
public int getId() {
return mId;
}
public void setId(int id) {
mId = id;
}
public int getImportant() {
return mImportant;
}
public void setImportant(int important) {
mImportant = important;
}
public String getContent() {
return mContent;
}
public void setContent(String content) {
mContent = content;
}
}
现在,您将创建一个数据库代理。同样,这个代理将把简单的应用调用转换成较低级别的 SQLite API 调用。在 com.apress.gerber.reminders 包中创建一个名为RemindersDbAdapter
的新类。将清单 5-9 中的代码直接放在新创建的 RemindersDbAdapter 类中。当您解析导入时,您会注意到在 Android SDK 中找不到 DatabaseHelper。我们将在后续步骤中定义 DatabaseHelper 类。此代码定义了列名和索引;一个TAG
用于测井;两个数据库 API 对象;数据库名称、版本和主表名称的一些常量;上下文对象;和用于创建数据库的 SQL 语句。
Listing 5-9. Code to be placed inside the RemindersDbAdapter class
//these are the column names
public static final String COL_ID = "_id";
public static final String COL_CONTENT = "content";
public static final String COL_IMPORTANT = "important";
//these are the corresponding indices
public static final int INDEX_ID = 0;
public static final int INDEX_CONTENT = INDEX_ID + 1;
public static final int INDEX_IMPORTANT = INDEX_ID + 2;
//used for logging
private static final String TAG = "RemindersDbAdapter";
private DatabaseHelper mDbHelper;
private SQLiteDatabase mDb;
private static final String DATABASE_NAME = "dba_remdrs";
private static final String TABLE_NAME = "tbl_remdrs";
private static final int DATABASE_VERSION = 1;
private final Context mCtx;
//SQL statement used to create the database
private static final String DATABASE_CREATE =
"CREATE TABLE if not exists " + TABLE_NAME + " ( " +
COL_ID + " INTEGER PRIMARY KEY autoincrement, " +
COL_CONTENT + " TEXT, " +
COL_IMPORTANT + " INTEGER );";
SQLite API
DatabaseHelper
是一个 SQLite API 类,用于打开和关闭数据库。它使用了Context
,这是一个抽象的 Android 类,提供对 Android 操作系统的访问。DatabaseHelper
是一个自定义类,必须由你定义。使用清单 5-10 中的代码将DatabaseHelper
实现为RemindersDbAdapter
的内部类。将此代码放在 RemindersDbAdapters 的末尾,但仍在 RemindersDbAdapters 的大括号内。
Listing 5-10. RemindersDbAdapter
private static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
Log.w(TAG, DATABASE_CREATE);
db.execSQL(DATABASE_CREATE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
+ newVersion + ", which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
onCreate(db);
}
}
DatabaseHelper
扩展了SQLiteOpenHelper
,这有助于用特殊的回调方法维护数据库。回调方法是运行时环境将在应用的整个生命周期中调用的方法,它们使用提供的SQLiteDatabase db
变量来执行 SQL 命令。构造函数是初始化数据库的地方。构造函数将数据库名称和版本传递给它的超类;然后超类做建立数据库的艰苦工作。当运行时需要创建数据库时,会自动调用onCreate()
方法。此操作仅运行一次,即应用首次启动且数据库尚未创建时。每当数据库需要升级时,就会调用onUpgrade()
方法,例如,如果开发人员更改了模式。如果您确实更改了数据库模式,请确保将DATABASE_VERSION
加 1,然后onUpgrade()
将管理剩余的部分。如果你忘记增加DATABASE_VERSION
,即使在调试构建模式下,你的程序也会崩溃。在前面的代码中,我们运行一个 SQL 命令来删除数据库中唯一的一个表,然后运行onCreate()
方法来重新创建该表。
清单 5-11 中的代码演示了如何使用DatabaseHelper
打开和关闭数据库。构造函数保存了一个Context
的实例,该实例被传递给DatabaseHelper
。open()
方法初始化助手并使用它来获取数据库的实例,而close()
方法使用助手来关闭数据库。在 RemindersDbAdapter 类中所有成员变量定义之后和DatabaseHelper
内部类定义之前添加此代码。当您解析导入时,使用android.database.SQLException
类。
Listing 5-11. Database Open and Close Methods
public RemindersDbAdapter(Context ctx) {
this.mCtx = ctx;
}
//open
public void open() throws SQLException {
mDbHelper = new DatabaseHelper(mCtx);
mDb = mDbHelper.getWritableDatabase();
}
//close
public void close() {
if (mDbHelper != null) {
mDbHelper.close();
}
}
清单 5-12 包含了处理tbl_remdrs
表中Reminder
对象的创建、读取、更新和删除的所有逻辑。这些通常被称为 CRUD 操作;CRUD 代表创建、读取、更新和删除。在 RemindersDbAdapter 类中的close()
方法之后添加下面的代码。
Listing 5-12. Database CRUD Operations
//CREATE
//note that the id will be created for you automatically
public void createReminder(String name, boolean important) {
ContentValues values = new ContentValues();
values.put(COL_CONTENT, name);
values.put(COL_IMPORTANT, important ? 1 : 0);
mDb.insert(TABLE_NAME, null, values);
}
//overloaded to take a reminder
public long createReminder(Reminder reminder) {
ContentValues values = new ContentValues();
values.put(COL_CONTENT, reminder.getContent()); // Contact Name
values.put(COL_IMPORTANT, reminder.getImportant()); // Contact Phone Number
// Inserting Row
return mDb.insert(TABLE_NAME, null, values);
}
//READ
public Reminder fetchReminderById(int id) {
Cursor cursor = mDb.query(TABLE_NAME, new String[]{COL_ID,
COL_CONTENT, COL_IMPORTANT}, COL_ID + "=?",
new String[]{String.valueOf(id)}, null, null, null, null
);
if (cursor != null)
cursor.moveToFirst();
return new Reminder(
cursor.getInt(INDEX_ID),
cursor.getString(INDEX_CONTENT),
cursor.getInt(INDEX_IMPORTANT)
);
}
public Cursor fetchAllReminders() {
Cursor mCursor = mDb.query(TABLE_NAME, new String[]{COL_ID,
COL_CONTENT, COL_IMPORTANT},
null, null, null, null, null
);
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;
}
//UPDATE
public void updateReminder(Reminder reminder) {
ContentValues values = new ContentValues();
values.put(COL_CONTENT, reminder.getContent());
values.put(COL_IMPORTANT, reminder.getImportant());
mDb.update(TABLE_NAME, values,
COL_ID + "=?", new String[]{String.valueOf(reminder.getId())});
}
//DELETE
public void deleteReminderById(int nId) {
mDb.delete(TABLE_NAME, COL_ID + "=?", new String[]{String.valueOf(nId)});
}
public void deleteAllReminders() {
mDb.delete(TABLE_NAME, null, null);
}
这些方法都使用SQLiteDatabase mDb
变量来生成和执行 SQL 语句。如果您熟悉 SQL,您可能会猜测这些 SQL 语句将采用INSERT
、SELECT
、UPDATE
或DELETE
的形式。
这两个创建方法使用一个特殊的ContentValues
对象,它是一个数据穿梭器,用于将数据值传递给数据库对象的insert
方法。数据库最终会将这些对象转换成 SQL insert
语句并执行它们。有两个read
方法,一个用于获取单个提醒,另一个用于获取光标来迭代所有提醒。您将在稍后的特殊Adapter
课程中使用Cursor
。
update
方法类似于第二个创建方法。然而,这个方法调用了低级数据库对象上的一个update
方法,该方法将生成并执行一个update
SQL 语句,而不是一个insert
。
最后,有两个delete
方法。第一个使用一个id
参数,并使用数据库对象为特定的提醒生成并执行一个delete
语句。第二种方法要求数据库生成并执行一个delete
语句,从表中删除所有提醒。
此时,您需要一种方法将提醒从数据库中取出并放入ListView
。清单 5-13 展示了通过扩展您之前看到的特殊的Adapter
Android 类将数据库值绑定到单个行对象的必要逻辑。在 com.apress.gerber.reminders 包中创建一个名为 RemindersSimpleCursorAdapter 的新类,并用下面的代码修饰它。在解析导入时,使用 Android . support . v4 . widget . simplecursoradapter 类。
Listing 5-13. RemindersSimpleCursorAdapter Code
public class RemindersSimpleCursorAdapter extends SimpleCursorAdapter {
public RemindersSimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags) {
super(context, layout, c, from, to, flags);
}
//to use a viewholder, you must override the following two methods and define a ViewHolder class
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return super.newView(context, cursor, parent);
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
super.bindView(view, context, cursor);
ViewHolder holder = (ViewHolder) view.getTag();
if (holder == null) {
holder = new ViewHolder();
holder.colImp = cursor.getColumnIndexOrThrow(RemindersDbAdapter.COL_IMPORTANT);
holder.listTab = view.findViewById(R.id.row_tab);
view.setTag(holder);
}
if (cursor.getInt(holder.colImp) > 0) {
holder.listTab.setBackgroundColor(context.getResources().getColor(R.color.orange));
} else {
holder.listTab.setBackgroundColor(context.getResources().getColor(R.color.green));
}
}
static class ViewHolder {
//store the column index
int colImp;
//store the view
View listTab;
}
}
我们用ListView
注册Adapter
来填充提醒。在运行时,当用户加载和滚动列表时,ListView
将重复调用Adapter
上的bindView()
方法和屏幕上的View
对象。用列表项填充这些视图是Adapter
的工作。在这个代码示例中,我们使用了名为SimpleCursorAdapter
的Adapter
的子类。这个类使用一个Cursor
对象,它跟踪表中的行。
这里你可以看到一个ViewHolder
模式的例子。这是一个众所周知的 Android 模式,其中一个小的ViewHolder
对象作为标签附加在每个视图上。这个对象通过使用来自数据源的值为列表中的View
对象添加装饰,在这个例子中是Cursor
。ViewHolder
被定义为具有两个实例变量的静态内部类,一个用于重要表列的索引,另一个用于您在布局中定义的row_tab
视图。
bindView()
方法首先调用超类方法,该方法将光标的值映射到视图中的元素。然后,它检查是否有一个持有者被附加到标签上,如果需要,创建一个新的持有者。然后,bindView()
方法通过使用重要的列索引和您之前定义的row_tab
来配置 holder 的实例变量。找到或配置持有者后,它使用当前提醒中的COL_IMPORTANT
常量的值来决定对row_tab
使用哪种颜色。该示例使用了新的橙色,您需要将它添加到您的colors.xml: <color name="orange">#ffff381a</color>
中。
之前您使用了一个ArrayAdapter
来管理模型和视图之间的关系。SimpleCursorAdapter
遵循相同的模式,尽管它的模型是 SQLite 数据库。对清单 5-14 进行更改,以使用新的 RemindersDbAdapter 和 RemindersSimpleCursorAdapter。
Listing 5-14. RemindersActivity Code
public class RemindersActivity extends ActionBarActivity {
private ListView mListView;
private RemindersDbAdapter mDbAdapter;
private RemindersSimpleCursorAdapter mCursorAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_reminders);
mListView = (ListView) findViewById(R.id.reminders_list_view);
mListView.setDivider(null);
mDbAdapter = new RemindersDbAdapter(this);
mDbAdapter.open();
Cursor cursor = mDbAdapter.fetchAllReminders();
//from columns defined in the db
String[] from = new String[]{
RemindersDbAdapter.COL_CONTENT
};
//to the ids of views in the layout
int[] to = new int[]{
R.id.row_text
};
mCursorAdapter = new RemindersSimpleCursorAdapter(
//context
RemindersActivity.this,
//the layout of the row
R.layout.reminders_row,
//cursor
cursor,
//from columns defined in the db
from,
//to the ids of views in the layout
to,
//flag - not used
0);
//the cursorAdapter (controller) is now updating the listView (view)
//with data from the db (model)
mListView.setAdapter(mCursorAdapter);
}
//Abbreviated for brevity
}
如果此时运行应用,您将不会在列表中看到任何内容;该屏幕将完全是空的,因为您的最后一次更改插入了 SQLite 功能来代替示例数据。按 Ctrl+K | Cmd+K 并提交您的更改,同时显示消息“为提醒添加 SQLite 数据库持久性并为重要提醒添加新颜色”。作为一项挑战,您可能会尝试找出如何通过使用新的RemindersDbAdapter
来添加示例项。这将在下一章讨论,所以你可以向前看并检查你的工作。
摘要
至此,你有了一个成熟的 Android 应用。在这一章中,你学习了如何建立你的第一个 Android 项目,并使用 Git 控制它的源代码。您还探索了如何在设计和文本模式下编辑 Android 布局。您已经看到了在操作栏中创建溢出菜单的演示。本章最后探讨了ListViews
和Adapters
,并将数据绑定到内置的 SQLite 数据库。在下一章中,您将通过添加创建和编辑提醒的功能来完善应用。