安卓编程初学者手册第三版(一)
原文:
zh.annas-archive.org/md5/ceefdd89e585c59c20db6a7760dc11f1译者:飞龙
前言
您是否正在尝试开始编程职业,但还没有找到合适的方式?您是否有一个很棒的应用程序想法,但不知道如何使其成为现实?如果是这样,那么这本书就是为您而写的!
本更新的第三版《Android 初学者编程》将是您从头开始创建 Android 应用程序的伴侣。我们将向您介绍在 Android 环境中编程的所有基本概念,从 Java 的基础知识到使用 Android API。所有示例都使用最新的 API 类,并且是在官方的 Android 开发环境 Android Studio 中创建的,这有助于加速您的应用程序开发过程。
在这个速成课程之后,我们将深入研究 Android 编程,您将学习如何通过片段创建具有专业标准 UI 的应用程序,并使用 SQLite 存储用户数据。此外,您还将了解如何使您的应用程序多语言化,用手指绘制到屏幕上,并处理图形、声音和动画。
通过本书,您将准备好开始在 Android 和 Java 中构建自己的定制应用程序。
本书适合人群
本书适合您如果您完全是 Java、Android 或编程的新手,并且想要制作 Android 应用程序。本书还将作为一个复习,供那些已经有使用 Java 在 Android 上经验的人使用,以帮助您提高知识并通过早期项目快速进步。
本书涵盖内容
第一章《开始 Android 和 Java》将帮助您立即开始开发 Android 应用程序,不浪费任何时间。我们将探讨 Android 的优势,Android 和 Java 究竟是什么,它们如何工作和相互补充,以及作为未来开发人员对我们意味着什么。随后,我们将设置所需的软件,以便我们可以构建和部署一个简单的第一个应用程序。
第二章《初次接触:Java、XML 和 UI 设计师》解释了在这个阶段,我们已经拥有了一个可工作的 Android 开发环境,并且已经构建和部署了我们的第一个应用程序。我们需要探索这个自动生成的代码,以便我们可以开始了解 Android,然后学习如何在这个有用的模板上构建。
第三章《探索 Android Studio 和项目结构》解释了如何创建和运行另外两个 Android 项目。这些练习的目的是更深入地探索 Android Studio 和 Android 项目的结构。除了了解我们项目的组成部分之外,确保我们充分利用模拟器也是有益的。
第四章《使用布局和 Material Design 入门》涵盖了构建另外三种布局的内容,这些布局仍然相当简单,但比我们迄今为止所做的要进一步。在我们动手之前,我们将快速介绍 Material Design 的概念。我们还将介绍名为 LinearLayout、ConstraintLayout 和 TableLayout 的不同类型的布局。我们还将编写一些 Java 代码,以在单个应用/项目中在不同的布局之间进行切换。这是第一个将多个主题整合在一个整洁包裹中的重要应用程序。
第五章《使用 CardView 和 ScrollView 创建美丽的布局》是在我们花一些时间专注于 Java 和面向对象编程之前的最后一章布局。我们将对我们已经遇到的一些不同属性进行正式化学习,并且还将介绍另外两种很酷的布局:ScrollView 和 CardView。最后,我们将在平板模拟器上运行一个 CardView 项目。
第六章《Android 生命周期》将使我们熟悉 Android 应用程序的生命周期。生命周期是所有 Android 应用程序与 Android 操作系统交互的方式。我们将看到应用程序从创建到销毁经历的生命周期阶段,以及这如何帮助我们根据我们想要实现的目标来放置我们的 Java 代码。
第七章《Java 变量、运算符和表达式》涵盖了 Java 的核心基础知识:放入类和我们创建的方法中的代码,以及代码作用的数据。在这一章中,我们将专注于数据。我们将深入学习如何编写我们自己的 Java 代码。在本章结束时,您将能够轻松编写创建和使用 Android 中数据的 Java 代码。
第八章《Java 决策和循环》解释了我们如何根据变量的值采取行动。我们将使用if、else和switch来在 Java 中做出决策。我们还将使用while、do-while、for和break来研究 Java 中的循环。
第九章《学习 Java 方法》更深入地研究了方法,因为尽管我们知道可以调用它们来执行它们的代码,但它们比我们迄今为止讨论的要复杂得多。
第十章《面向对象编程》解释了在 Java 中,类对几乎所有事情都是基础的。我们将开始理解为什么上世纪 90 年代初太阳微系统的软件工程师们会以他们的方式制作 Java。我们已经讨论了重用其他人的代码,特别是 Android API,但在这一章中,我们将真正掌握它的工作原理,并了解面向对象编程以及如何使用它。
第十一章《更多面向对象编程》是我们对面向对象编程的第二部分(理论和实践)。我们已经简要讨论了封装、继承和多态的概念,但在这一章中,我们将在一些演示应用程序中看到它们的实际应用。虽然这些工作示例将展示这些概念的最简单形式,但这仍然是掌握通过 Java 代码控制我们的 XML 布局的重要一步。
第十二章《堆栈、堆和垃圾收集器》揭示了 Java 和我们的 XML 布局之间的缺失链接,使我们有能力向我们的应用程序添加各种小部件,就像以前一样,但这次我们将能够通过我们的 Java 代码控制它们。在这一章中,我们将控制一些相当简单的 UI 元素,如按钮和文本视图。为了使我们能够理解发生了什么,我们需要更多地了解 Android 设备中的内存以及其中的两个区域——堆栈和堆。
第十三章《匿名类-让 Android 小部件栩栩如生》解释了现在我们对 Android 应用程序的布局和编码有了很好的概述,以及我们对面向对象编程的新见解以及如何从我们的 Java 代码中操作 UI,我们已经准备好通过匿名类与调色板中的更多小部件进行实验。在这一章中,我们将通过回到 Android Studio 调色板并查看我们还没有完全使用过的半打小部件来进行大量的多样化。完成后,我们将把它们放入布局中,并练习用 Java 代码操作它们。
第十四章,安卓对话框窗口,介绍了如何向用户呈现弹出式对话框窗口。然后我们将把我们所知道的内容都放入我们的第一个主要应用程序 Note to self 的第一阶段。在这一章和接下来的四章中,我们还将学习关于新的安卓和 Java 特性,然后利用我们新获得的知识每次增强 Note to self 应用程序。在每一章中,我们还将构建一些与主应用程序分开的小应用程序。
第十五章,数组、映射和随机数,讨论了 Java 数组,它允许我们以有组织和高效的方式操纵大量数据。我们还将使用与数组有密切关系的 Java 关系,ArrayList,并看到它们之间的区别。一旦我们能够处理大量数据,我们将看到安卓 API 为了帮助我们轻松地将我们新获得的数据处理技能连接到用户界面而做了哪些工作。
第十六章,适配器和回收器,首先介绍了适配器和列表的理论。我们将学习如何在 Java 代码中扩展 RecyclerAdapter 并添加一个 RecyclerView,它作为我们的用户界面的列表,然后通过安卓 API 的明显魔力将它们绑定在一起,使 RecyclerView 显示 RecyclerAdapter 的内容,并允许用户滚动查看内容。
第十七章,数据持久性和共享,探讨了将数据保存到安卓设备永久存储的几种不同方式。同时,我们还将首次向我们的应用程序添加第二个活动。在实现一个独立的“屏幕”,比如我们的应用中的设置屏幕时,将新建一个活动是有意义的。我们将学习如何添加一个活动并在它们之间引导用户。
第十八章,本地化,解释了如何添加额外的语言。我们将看到通过字符串资源的正确方式添加文本在添加多种语言时对我们有什么好处。
第十九章,动画和插值,介绍了如何使用动画类使我们的用户界面不那么静态,更有趣。正如我们所期望的那样,安卓 API 将允许我们用相对简单的代码做一些相当先进的事情,动画类也不例外。
第二十章,绘图图形,致力于安卓 Canvas 类和一些相关类,比如 Paint、Color 和 Bitmap。这些类的结合在绘制屏幕时带来了巨大的力量。如果我们想制作一个绘图应用程序、绘制图表,或者可能是一个游戏,我们需要控制安卓设备提供的每个像素。
第二十一章,线程和启动实时绘图应用程序,开始了下一个应用程序。这个应用程序将是一个儿童风格的绘图应用程序,用户可以用手指在屏幕上绘图。然而,这个绘图应用程序将略有不同。用户绘制的线条将由粒子系统组成,这些粒子系统会爆炸成成千上万的碎片。我们将把这个项目称为 Live Drawing。
第二十二章,粒子系统和处理屏幕触摸,解释了如何创建在这个实时系统中存在和演变的实体,就像它们有自己的思维,并形成用户可以实现的绘图的外观。我们还将看到用户如何通过学习如何响应与屏幕的交互来绘制这些实体。这与与 UI 布局中的小部件进行交互是不同的。
第二十三章,支持不同版本的 Android、声音效果和 Spinner 小部件,解释了我们如何检测和处理不同版本的 Android。然后,我们将能够研究 SoundPool 类以及根据应用程序运行的 Android 版本不同的使用方式。在这一点上,我们可以将我们学到的一切投入到制作一个很酷的声音演示应用程序中,这也将向我们介绍一个新的 UI 小部件——Spinner。
第二十四章,设计模式、多个布局和片段,更多关于您未来应用程序的内容,而不是本书迄今为止的任何内容。我们将看一些 Java 和 Android 的方面,您可以将其用作制作更加令人兴奋和复杂的应用程序的框架或模板,同时保持代码的可管理性。此外,我将建议进一步学习的领域,这本书根本没有足够的空间来涉及。
第二十五章,构建一个简单的图库应用程序,解释了如何使用分页和图像滑动创建应用程序,就像您可能在照片库应用程序中找到的那样。此外,使用 RecyclerView 小部件,我们将有选择地仅加载当前页面所需的数据,以及可能是前一页和下一页页面的数据。
第二十六章,带有导航抽屉和片段的高级 UI,涵盖了(可以说是)最高级的 UI。 NavigationView 可以通过在创建新项目时选择它作为模板来简单创建。然后,我们将检查自动生成的代码,并学习如何与其交互。然后,我们将利用我们对 Fragment 的所有了解来填充每个“抽屉”以具有不同的行为和视图。
第二十七章,Android 数据库,解释了如果我们要制作提供给用户重要功能的应用程序,那么几乎可以肯定我们需要一种管理、存储和过滤大量数据的方式。JSON 和 SharedPreferences 类有它们的用处,但是在某个时候,我们需要转向使用真正的数据库来解决现实世界的问题。Android 使用 SQLite 数据库管理系统,正如您所期望的那样,有一个 API 使其尽可能简单。
第二十八章,告别前的快速聊天,结束了我们的旅程。本章简单地包括了一些想法和指针,您可能在匆忙离开并制作自己的应用程序之前想要看一看。
为了充分利用本书
要成功阅读本书,您根本不需要任何经验。如果您对自己选择的操作系统(Windows、macOS 或 Linux)有信心,您可以在学习 Java 编程语言的同时学习制作 Android 应用程序。学习开发专业质量的应用程序是任何人都可以开始并坚持下去的旅程。
如果您之前有编程(Java 或任何其他语言)、Android 或其他开发经验,那么您将在前几章中取得更快的进展。
如果您使用本书的数字版本,我们建议您自己输入代码或通过 GitHub 存储库访问代码(链接在下一节中提供)。这样做将有助于避免与复制和粘贴代码相关的任何潜在错误。
下载示例代码文件
您可以从 GitHub 上下载本书的示例代码文件github.com/PacktPublishing/Android-Programming-for-Beginners-Third-Edition。如果代码有更新,它将在现有的 GitHub 存储库上进行更新。
我们还有来自我们丰富书籍和视频目录的其他代码捆绑包可供下载github.com/PacktPublishing/。去看看吧!
下载彩色图像
我们还提供了一个 PDF 文件,其中包含本书中使用的屏幕截图/图表的彩色图像。您可以在这里下载:static.packt-cdn.com/downloads/9781800563438_ColorImages.pdf。
使用的约定
本书中使用了许多文本约定。
文本中的代码:指示文本中的代码词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 句柄。以下是一个例子:“最后一个成员变量是一个LayoutInflater实例,它将用于填充pager_item.xml的每个实例。”
代码块设置如下:
@Override
public int getCount() {
return images.length;
}
当我们希望引起您对代码块的特定部分的注意时,相关行或项将以粗体显示:
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
任何命令行输入或输出都将按如下方式编写:
$ mkdir css
$ cd css
粗体:表示新术语、重要单词或屏幕上看到的单词。例如,菜单或对话框中的单词会在文本中以这种方式出现。以下是一个例子:“从管理面板中选择系统信息。”
提示或重要说明
会出现这样。
第一章:开始 Android 和 Java
欢迎使用《初学者的 Android 编程第三版》。在第一章中,我们将立即开始开发 Android 应用程序。我们将看看 Android 有什么好处,Android 和 Java 究竟是什么,它们如何工作和相互补充,以及作为未来开发者,这对我们意味着什么。随后,我们将快速设置所需的软件,以便我们可以构建和部署一个简单的第一个应用程序。
注意
我的目标是使本书保持最新。请查看以下网页,了解自书印刷以来 Android Studio 的任何更改讨论和提示:gamecodeschool.com/books/android-programming-for-beginners-3rd-edition#android-studio-updates。
在本章结束时,我们将完成以下内容:
-
了解了第三版的新内容
-
了解了 Java 和 Android 如何相互配合
-
设置我们的开发环境——Android Studio——它负责构建我们将在接下来学习的 Android 应用程序所涉及的所有组件
-
了解了Java 开发工具包(JDK)和 Android 应用程序编程接口(API)以及我们如何通过 Android Studio 使用它们
-
构建我们的第一个 Android 应用程序
-
在 Android 模拟器上部署应用程序
-
在 Android 模拟器和真实设备上运行我们的应用程序
这是很多内容,让我们开始吧。
技术要求
以下是使用 Android Studio 及其相关工具进行 Android 开发的官方技术要求。但这些是绝对的最低要求。请参阅“设置 Android Studio”部分以获取更多详细信息。
Windows 的要求如下:
-
Microsoft® Windows® 7/8/10(64 位)
-
至少需要 4GB 的 RAM;建议 8GB 的 RAM
-
至少需要 2GB 的可用磁盘空间;建议 4GB(500MB 用于集成开发环境(IDE)+ 1.5GB 用于 Android 软件开发工具包(SDK)和模拟器系统镜像)
-
最低屏幕分辨率为 1,280 x 800
Mac 的要求如下:
-
Mac® OS X® 10.10(Yosemite)或更高版本,最高为 10.14(macOS Mojave)
-
至少需要 4GB 的 RAM;建议 8GB 的 RAM
-
至少需要 2GB 的可用磁盘空间;建议 4GB(500MB 用于 IDE + 1.5GB 用于 Android SDK 和模拟器系统镜像)
-
最低屏幕分辨率为 1,280 x 800
Linux 的要求如下:
-
GNOME 或 KDE 桌面
-
在基于 Debian 的 gLinux 上进行了测试
-
64 位发行版,能够运行 32 位应用程序
-
GNU C 库(glibc)2.19 或更高版本
-
至少需要 4GB 的 RAM;建议 8GB 的 RAM
-
至少需要 2GB 的可用磁盘空间;建议 4GB(500MB 用于 IDE + 1.5GB 用于 Android SDK 和模拟器系统镜像)
-
最低屏幕分辨率为 1,280 x 800
您可以在 GitHub 上找到本章的代码文件github.com/PacktPublishing/Android-Programming-for-Beginners-Third-Edition/tree/main/chapter%2001。
第三版有什么新内容?
与第一版相比,第二版增加了大量额外的主题。不幸的是,平装书只能容纳有限的页数。因此,这一版着重于改进 Java、Android 和应用开发概念的教学方式。我们重新思考了主题的解释方式,并使其比以前更加直观。此外,我设法加入了大约十几个新的迷你主题。这些内容要么是 Java 基础知识,比如在早期版本中没有涵盖的变量类型,要么是新的 Android Studio 功能,比如分析器,或者是经典的编程概念,比如方法递归和我们代码的实时调试。希望这第三版能让您的 Android 和 Java 之旅更加顺利和完整。
为什么选择 Java 和 Android?
当 Android 于 2008 年首次出现时,与苹果 iPhone/iPad 上更时尚的 iOS 相比,它显得有些沉闷。但通过迅速推出各种各样的手机产品,既符合实际价格敏感的人群,又符合时尚和科技精通的人群,Android 用户数量迅速增长。
对于许多人来说,包括我自己在内,为 Android 开发是最有意义的业余爱好和事业。
快速地将一个想法的原型组装起来,完善它,然后决定运行并将其连接成一个完全成熟的应用程序,这是一个如此令人兴奋和有意义的过程。任何编程都可以很有趣,我一生都在编程,但为 Android 创作某种程度上是非常有意义的。
确切地定义这种情况为什么会发生是相当困难的。也许是因为这个平台是免费和开源的。您可以在不需要大型控制性公司的许可的情况下分发您的应用程序 - 没有人可以阻止您。与此同时,您还可以在亚马逊应用商店和 Google Play 等成熟的、由公司控制的大众市场上分发应用程序。
更有可能的是,为 Android 开发带来如此良好的感觉的原因是设备本身的性质。它们是非常个人化的。您可以开发与人们生活互动的应用程序 - 教育、娱乐、讲故事等等 - 它就在他们的口袋里准备好了,在家里、工作场所或度假时。
当然,您可以为桌面构建更大的东西。但知道成千上万(甚至数百万)的人携带着您的作品并与朋友分享,这带来的不仅仅是一种兴奋。
事实上,为 Android 开发被认为是非常有技巧的,最成功的开发人员受到极大的钦佩,甚至崇敬。
如果所有这些空洞和精神上的东西对您毫无意义,那也没关系;为 Android 开发可以让您谋生,甚至让您致富。随着设备拥有量的持续增长,CPU 和 GPU 性能的不断提升,以及 Android 操作系统本身的不断演进,对专业应用程序开发人员的需求只会增长。
简而言之,最优秀的 Android 开发人员 - 更重要的是,拥有最好的想法和最大决心的 Android 开发人员 - 比以往任何时候都更受欢迎。没有人知道这些未来的 Android 应用程序开发人员是谁,他们甚至可能还没有写过他们的第一行 Java 代码。
那么,为什么不是每个人都是 Android 开发人员呢?显然,并不是每个人都会像我一样热衷于创造能够帮助人们改善生活的软件,但我猜测因为您正在阅读这篇文章,您可能会!
初学者的第一个绊脚石
不幸的是,对于那些和我一样热衷的人来说,进步的道路上存在一种玻璃墙,这让许多有抱负的 Android 开发人员感到沮丧。
Android 使用 Java 来制作应用程序。每本 Android 书籍,甚至那些针对所谓初学者的书籍,都假设读者至少具有中级水平的 Java 知识,大多数需要高级水平的知识。因此,良好到优秀的 Java 知识曾经是学习 Android 的先决条件。
不幸的是,在完全不同的上下文中学习 Java 有时可能会有点乏味,而您学到的大部分知识在 Android 世界中并不直接可转移。您可以理解为什么初学者对 Android 和 Java 经常望而却步。
但不一定非得这样。在这本书中,我已经把你在厚重的、专门针对初学者的 Java 书中学到的所有 Java 主题都精心安排成了四个多章节的应用程序和十几个快速的迷你应用程序,从一个简单的备忘录应用程序开始,然后逐渐发展成一个酷炫的绘图应用程序、一个数据库应用程序和一个可玩的游戏(可在线使用)。
如果您想成为专业的 Android 开发人员,或者只是想在学习 Java 和 Android 时更有乐趣,这本书会帮助您。
Java 和 Android 如何协同工作
在开始我们的 Android 探索之前,我们需要了解 Android 和 Java 如何一起工作。Android 是一个复杂的系统,但你不需要深入了解它才能制作出令人惊艳的应用程序。
在我们为 Android 用 Java 编写程序之后,我们点击一个按钮,我们的代码就会被转换成另一种形式,这种形式是 Android 可以理解的形式。这种形式被称为字节码,转换过程被称为编译。
然后,当用户安装我们的应用程序时,字节码会被另一个进程(称为Android Runtime(ART))转换为机器码。这是最快的执行格式。因此,如果你曾听说过不应该使用 Java 因为它很慢,那么你知道他们是错误的。Java 对程序员来说编程速度很快,然后在安装时转换为设备快速的机器码。还有什么比这更好的呢?
ART 不仅能够使我们的应用程序执行速度超快,而且还能降低电池使用。此外,ART 系统不仅仅创建机器码然后坐下来放松;它提供了钩子进入我们的应用程序,增强了应用程序在运行时的内存管理。这使得我们的应用程序运行更高效,并且,正如我们将在第十二章中看到的那样,堆栈、堆和垃圾收集器,更容易通过处理内存管理的关键方面来编写。
ART 本身是用另一种语言编写的软件系统,运行在一个特别适应的 Linux 操作系统的版本上。因此,用户所看到的 Android 本身只是在另一个操作系统上运行的应用程序。
Android 是一个子系统的集合。典型的 Android 用户看不到 Linux 操作系统,也不知道 ART 的存在,但它们都在那里运转。
系统的 Linux 部分的目的是隐藏 Android 运行的硬件和软件的复杂性和多样性,但同时暴露出所有有用的功能。这种功能的暴露有两种方式:
-
首先,系统本身必须能够访问硬件,它确实可以。
-
其次,这种访问必须是对程序员友好且易于使用的——这是因为 Android API。
让我们继续谈谈 Android API。
注意
这本书是关于学习 Java 并从头开始构建 Android 应用程序的,所以我不会深入探讨 Android 的工作原理。然而,如果你想了解更多,那么维基百科页面是一个很好的参考:en.wikipedia.org/wiki/Android_(operating_system。
理解 Android API
Android API 是一种使得做出非凡事情变得容易的代码。可以用一个简单的类比来理解,比如一台机器,也许是一辆汽车。当你踩油门时,引擎盖下会发生一大堆事情。我们不需要理解燃烧或燃油泵,因为一些聪明的工程师为我们制作了一个接口——在这种情况下,是一个机械接口:油门踏板。
例如,下面这行 Java 代码在本书的这个阶段可能看起来有点吓人,但它是 Android API 如何帮助我们的一个很好的例子:
locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
一旦你了解到这一行代码在太空搜索可用的卫星,然后与它们在地球轨道上通信,然后在地球表面检索你的精确纬度和经度,那么开始逐渐领略 Android API 与编译的字节码和 ART 的强大和深度就变得容易了。
当然,这段代码看起来有点具有挑战性——甚至在本书的这个阶段都是如此——但想象一下用其他方式与卫星交流试试看!
Android API 已经为我们编写了一大堆可以随意使用的 Java 代码。
注意
关于 Android 的代码行数有很多不同的估计。一些估计只有 100 万行,而一些估计高达 2000 万行。令人惊讶的是,尽管有如此庞大的代码量,Android 在编程圈中以“轻量级”而闻名。
我们必须问的问题,也是本书试图回答的问题是:
我们如何使用所有这些代码来做酷炫的事情?或者为了符合之前的类比,我们如何找到并操作 Android API 的踏板、方向盘和天窗?
这个问题的答案是 Java 编程语言以及 Java 旨在帮助程序员处理复杂性的事实。让我们稍微谈一下 Java 和面向对象编程(OOP)。
Java 是面向对象的
Java 是一种编程语言,比 Android 存在的时间长得多。它是一种面向对象的语言。这意味着它使用可重用的编程对象的概念。如果这听起来像技术术语,另一个类比会有所帮助。Java 使我们和其他人(比如 Android 开发团队)能够编写可以基于现实世界事物构建的 Java 代码,这是重要的部分:它可以被重复使用。
因此,使用汽车类比,我们可以问一个问题:如果一个制造商一天制造多辆汽车,他们是否为每辆汽车重新设计每个零件?
当然,答案是否定的。他们让高技能的工程师开发完全正确的组件,经过多年的磨练、改进和提高。然后,同样的组件被反复重复使用,偶尔进行改进。
如果你对我的类比挑剔,那么你可以指出每个汽车的组件仍然必须使用现实生活中的工程师或机器人等从原材料中构建出来。
这是真的。软件工程师在编写代码时所做的是构建对象的蓝图。然后我们使用 Java 代码从他们的蓝图创建对象,一旦我们有了那个对象,我们可以配置它,使用它,与其他对象组合,以及更多。
此外,除此之外,我们也可以设计自己的蓝图并从中制作对象。然后编译器将我们的定制创建转换(制造)成字节码。嘿,变戏法!我们有了一个 Android 应用程序。
在 Java 中,蓝图被称为类。当一个类被转化为一个真正工作的“东西”时,我们称之为类的对象或实例。
对象简洁
我们可以继续进行类比。然而,我们在这一点上关心的是以下内容。
Java 是一种允许我们编写一次代码然后重复使用的语言。这非常有用,因为它节省了我们的时间,并允许我们使用其他人的代码来执行我们可能没有时间或知识来编写的任务。大多数时候,我们甚至不需要看到这些代码,甚至不知道它是如何工作的!最后一个类比:我们只需要知道如何使用代码,就像我们需要学会如何驾驶汽车一样。
因此,Android 总部的一位聪明的软件工程师编写了一个非常复杂的 Java 程序,可以与卫星通信。然后,他们考虑如何使这段代码对所有想要开发使用用户位置做酷炫事情的 Android 程序员有用。其中一件事情是使获取设备在世界上的位置成为一个简单的一行任务。
因此,我们之前看到的一行代码引发了更多我们看不到、也不需要看到的代码。这是一个使用别人的代码使我们的代码变得无限简单的例子。
注
如果你不必看到所有的代码这个事实让你失望,那么我理解你的感受。当我们学习某样东西时,有些人希望了解每一个细节。如果你也是这样的话,那么请放心,学习 Android API 内部工作原理的最佳起点是按照 API 程序员的意图来使用它。在整本书中,我会定期指出更多学习机会,让你了解 Android API 的内部工作原理。此外,我们将编写一些可重复使用的类,有点像我们自己的 API,只是我们的类将专注于我们想要我们的应用程序做的事情。
欢迎来到面向对象编程(OOP)的世界。我会在每一章中不断提到 OOP,而在 第十章 中有关于它如何工作的大揭示,面向对象编程。
再告诉我一遍 - Android 究竟是什么?
在 Android 上,我们编写自己的 Java 代码,同时也使用 Android API 的 Java 代码。然后,这些代码被编译成字节码,并在用户安装时由 ART 转换成机器码,而机器码又与一个名为 Linux 的底层操作系统连接,处理着不同 Android 设备的复杂和极其多样的硬件。
Android 设备的制造商和个别硬件组件显然也知道这一点,他们编写了称为驱动程序的高级软件,确保他们的硬件(CPU、GPU、GPS 接收器、存储芯片、硬件接口等)可以在底层 Linux 操作系统上运行。
字节码(以及其他一些资源)被放在一个称为Android 应用程序包(APK)的文件包中,这是 ART 运行以准备我们的应用程序给用户使用所需的东西。
注意
不需要记住我们的代码与硬件交互时经历的步骤的细节。只需要理解我们的 Java 代码经历了一些自动化过程,成为我们将发布到 Google Play 商店的应用程序。
接下来的问题是“所有这些 Java 编码和编译成字节码以及 APK 打包到底发生在哪里?”。让我们看看我们将要使用的开发环境。
Android Studio
开发环境 是一个术语,指的是在一个地方拥有你开发所需的一切并准备就绪。我们需要两样东西才能开始:
-
我们谈到了编译我们的 Java 代码,以及其他人的 Java 代码,将其转换成用户 Android 设备上可执行的机器码。为了使用 Java 代码,我们需要一些名为JDK的免费软件。JDK 包括了更多其他人的代码,这些代码与 Android API 是分开的。
-
开发 Android 需要一整套工具,当然还需要 Android API。这整套要求被统称为 Android SDK。幸运的是,下载并安装一个应用程序就能将这些东西捆绑在一起。这个应用程序叫做 Android Studio。
Android Studio 是一个集成开发环境,将处理编译我们的代码和与 JDK 和 Android API 进行链接的所有复杂性。一旦安装了 Android Studio,我们可以在这个单一应用程序中完成所有需要的工作,并将我们讨论过的许多复杂性放在脑后。
提示
随着时间的推移,这些复杂性将变得自然而然。不需要掌握它们才能取得进一步的进展。
所以,我们最好开始使用 Android Studio。
设置 Android Studio
设置 Android Studio 相当简单,尽管有点冗长。拿些点心,然后按照以下步骤开始。本教程将把 Android Studio 安装到 D 驱动器上。我选择了 D 驱动器,因为这是一个大型安装,一旦我们下载了所有内容,大约有 12GB,而且许多 PC 上的 D 驱动器通常比 C 驱动器更大,有更多的可用空间。如果您希望安装在 C 驱动器(或任何其他驱动器),那么这些说明应该很容易调整:
-
访问
developer.android.com/studio并单击下载 Android Studio按钮。这将开始下载最新稳定版本的 Windows。您需要接受条款和条件才能开始下载。 -
在等待下载完成时,在 D 驱动器的根目录上创建一个名为
Android的新文件夹。在Android文件夹内,创建另一个名为Android Studio的新文件夹。返回到Android文件夹并创建另一个名为Projects的新文件夹。这是我们将在整本书中创建的所有项目文件的存放位置。创建另一个名为Sdk的新文件夹,这是我们将要求安装程序安装 Android SDK 的位置。现在您应该有一个看起来像这样的D:\Android文件夹:
图 1.1 – D:\Android 文件夹
-
下载完成后,找到已下载的文件。它将被称为
android-studio-ide....。双击该文件运行它。 -
您将被要求授予安装程序管理权限,然后您可以单击下一步开始安装。在选择组件屏幕上,确保Android Studio和Android 虚拟设备选项都被选中,然后单击下一步按钮:
图 1.2 – 选择组件屏幕
- 在
D:\Android\Android Studio,然后左键单击确定按钮:
图 1.3 – 配置设置窗口
-
在前面的截图中,单击下一步按钮。在选择开始菜单文件夹窗口上,单击安装以接受默认选项。安装的第一部分现在将进行。
-
一旦收到安装完成消息,单击下一步按钮。然后可以单击完成按钮。
Android Studio 应该会自动启动。如果没有,您可以在 Windows 开始菜单中找到并启动 Android Studio 应用程序。
-
您将收到一条消息,提示您缺少 SDK(除非这不是您第一次使用 Android Studio)。单击下一步继续。
-
在
D:\Android\Sdk,如下截图所示:
图 1.4 – SDK 组件设置屏幕
-
单击下一步按钮。
-
在验证设置窗口上,单击完成按钮。Android Studio 现在将下载一些文件并完成安装。这可能需要几分钟或更长时间,您可能会再次被提示允许访问您的 PC。
-
当过程结束时,单击完成按钮。
您将看到下一个 Android Studio 欢迎屏幕:
图 1.5 – Android Studio 欢迎屏幕
如果您要直接进行下一节,那么保持此屏幕。如果愿意,可以关闭它,然后在准备好继续时,像运行任何其他应用程序一样,从 Windows 开始菜单中运行 Android Studio。
让我们谈谈 Android 应用程序包括的所有不同内容。
什么构成了一个 Android 应用程序?
我们已经知道,我们将编写的 Java 代码本身将使用其他人的 Java 代码,并将被编译成字节码,然后在用户的 Android 设备上转换为机器代码。除此之外,我们还将添加和编辑其他包含在最终 APK 中的文件。这些文件被称为 Android 资源。
Android 资源
我们的应用程序将包括图像、声音和用户界面(UI)布局等资源,这些资源保存在与 Java 代码分开的文件中。我们将在本书的过程中慢慢介绍它们。
它还将包括具有我们应用程序文本内容的文件。通过单独的文件引用应用程序中的文本是一种惯例,因为这样做可以使它们易于更改,并且可以创建适用于不同语言和地理区域的应用程序。
此外,尽管有使用可视化设计工具实现应用程序的实际 UI 布局的选项,但实际上是由 Android 从基于文本的文件中读取的。
当然,Android(或任何计算机)无法像人类一样阅读和识别文本。因此,我们必须以高度组织和预定义的方式呈现我们的资源。为此,我们将使用.xml。
你不需要记住这一点,因为我们将在整本书中不断回到这个概念。
Android 的 Java 代码结构
除了这些资源之外,值得注意的是,在 Android 中使用的 Java 代码具有其代码结构。我们可以利用数百万行代码。显然,这些代码需要以便于查找和引用的方式进行组织。它们被组织成特定于 Android 的包。
包
每当我们创建一个新的 Android 应用程序时,我们将选择一个称为包的唯一名称。我们将在构建我们的第一个 Android 应用程序部分中看到我们是如何做到这一点的。包通常被分成子包,以便与其他类似的包一起分组。我们可以简单地将其视为文件夹和子文件夹,这几乎就是它的实质。
我们可以将 Android API 提供给我们的所有包视为代码库中的代码。我们将使用的一些常见 Android 包包括以下内容:
-
android.graphics -
android.database -
android.view.animation
正如你所看到的,它们被安排和命名,以使其中的内容尽可能明显。
注意
如果你想了解 Android API 的深度和广度,可以查看 Android 包索引:developer.android.com/reference/packages。
类
之前,我们了解到我们可以将可重用的代码蓝图转换为对象的文件称为.java文件扩展名。
方法
在 Java(因此也是 Android)中,我们将类进一步分成执行不同操作的部分。我们称这些以行动为导向的部分为方法。通常,我们将使用类的方法来访问所有这些数百万行代码中提供的功能。
我们不需要阅读代码。我们只需要知道哪个类有我们需要的内容,它属于哪个包,以及类内的哪些方法能给我们精确的结果。
下一个图表显示了 Android API 的表示。我们将编写的代码结构将类似于此示例的结构,尽管我们通常每个应用程序只有一个包。
当然,由于 Java 的面向对象性质,我们只会使用 API 中的部分功能。还要注意,每个类都有其自己独特的数据。通常,如果你想访问类中的数据,你需要有该类的对象:
图 1.6 - Android API 的表示
您不需要记住这一点,因为我们将在整本书中不断回到这个概念。
到本章结束时,我们将导入多个包,以及其中的几十个类,并且我们还将使用其中许多方法。到第二章**结束时,首次接触:Java、XML 和 UI 设计,我们甚至将编写我们自己的方法。现在我们可以开始第一个应用程序了。
构建我们的第一个 Android 应用程序
在编程中,传统上新学生的第一个应用程序会使用他们正在使用的语言/操作系统向世界打招呼。我们将快速构建一个只做这件事的应用程序,并且在第二章**结束时,首次接触:Java、XML 和 UI 设计,我们将超越这一点,并添加一些在用户按下按钮时响应的按钮。
注意
本章结束时的完整代码在第一章文件夹中的下载包中供您参考。但是,您不能简单地复制和粘贴这段代码!您仍然需要按照本章(以及所有项目开头)中解释的项目创建阶段进行操作,因为 Android Studio 在幕后做了大量工作。一旦您熟悉了这些步骤,并理解了哪些代码是由您作为程序员输入的,哪些代码/文件是由 Android Studio 生成的,那么您就能够通过复制和粘贴我在下载包中提供的文件来节省时间和输入。
按照以下步骤开始项目:
- 以与运行任何其他应用程序相同的方式运行 Android Studio。例如,在 Windows 10 上,启动图标会出现在开始菜单中。
提示
如果提示从…导入 Studio 设置,请选择不导入设置。
- 您将看到 Android Studio 的欢迎屏幕,如下截图所示。找到开始一个新的 Android Studio 项目选项,并单击它:
图 1.7 - Android Studio 欢迎屏幕
- 接下来的窗口是选择项目模板。
这些是 Android Studio 可以根据您要开发的应用程序类型为您生成的一些有用的项目模板。我们将使用基本活动选项。Android Studio 将自动生成少量代码和一些资源来启动我们的项目。我们将在下一章详细讨论代码和资源。
- 选择基本活动。以下是选择项目模板窗口,其中选择了基本活动选项的图片:
图 1.8 - 选择项目模板窗口
-
确保基本活动被选中,就像前面的截图中一样,然后点击下一步。
-
之后,Android Studio 将弹出
Hello World,文件的位置将是我们在设置 Android Studio部分中创建的Projects文件夹。
包名可以是几乎任何你喜欢的东西。如果您有一个网站,您可以使用com.yourdomainname的格式。如果没有,可以使用我的域名com.gamecodeschool.helloworld,或者您自己编造的东西。这只有在您要发布时才重要。
为了明确起见,如果您无法清楚地看到以下截图中的细节,这里是我使用的值。请记住,根据您对包名和项目位置的选择,您的值可能会有所不同:
提示
请注意,应用程序名称中Hello和World之间有一个空格,但项目位置没有,如果有空格将无法工作。
- 下一张截图显示了一旦您输入了所有信息的配置您的项目屏幕:
图 1.9 - 配置您的项目屏幕
- 在上一张截图中,您可以看到 Android Studio 根据输入的信息自动生成了一个包名称。我的是com.gamecodeschool.helloworld。您的可能相同,也可能不同;这并不重要。
注意
您可以使用几种不同的语言编写安卓应用程序,包括 C++和 Kotlin。与使用 Java 相比,每种语言都有各种优缺点。学习 Java 将是其他语言的很好入门,并且 Java 也是安卓的官方语言之一。目前 Play 商店上大多数热门应用和游戏都是用 Java 编写的。
您还可以看到最低 SDK选项。将其保留为默认设置,但请注意,写作时默认设置可能与您的设置不同。
注意
我们已经知道安卓 SDK 是我们将用来开发应用程序的代码包集合。像任何一个好的 SDK 一样,安卓 SDK 定期更新,每次有重大更新时,版本号都会增加。简单来说,版本号越高,您可以使用的新功能就越多;版本号越低,我们的应用程序就能在更多设备上运行。目前,安卓果冻豆将为我们提供许多出色的功能,并且几乎 100%兼容当前使用的安卓设备。如果在阅读时,Android Studio 建议使用更新的 API 和安卓版本,那就选择那个吧。
如果您在未来的某个时候阅读本书,那么最低 SDK选项可能会默认为不同的内容,但本书中的代码仍将有效。
- 点击完成按钮,我们将运行应用程序,看看我们取得了什么成就。
注意
第一次创建新项目时,Android Studio 将启动另一个下载。Android Studio 将设置用于管理项目配置和部署的 Gradle 构建系统。这只会发生在第一个项目中。本书不需要了解 Gradle 的知识,但如果您感兴趣,简单的网络搜索将会揭示更多信息。
让我们看看我们的应用程序在运行中的情况。
到目前为止部署应用程序
在我们探索任何代码并学习我们的第一段 Java 代码之前,您可能会惊讶地发现我们已经可以运行我们的项目了。这只是一个相当无特色的应用程序,但由于我们将尽可能频繁地运行应用程序来检查我们的进度,现在让我们看看如何做到这一点。您有三个选择:
-
在 PC 上的模拟器上运行应用程序(Android Studio 的一部分)处于调试模式。
-
在 USB 调试模式下在真实的安卓设备上运行应用程序。
-
将应用程序导出为一个完整的安卓项目,可以上传到 Play 商店。
第一个选项(调试模式)是最容易设置的,因为我们在设置 Android Studio 时已经做过了。如果您有一台性能强大的 PC,您几乎不会注意到模拟器和真实设备之间的区别。然而,屏幕触摸是由鼠标点击模拟的,对用户体验的正确测试在我们将创建的一些后续应用中是不可能的,比如绘图应用。此外,您可能更喜欢偶尔在真实设备上测试您的创作——我知道我会。
第二个选项,使用真实设备,有几个额外的步骤,但一旦设置好,就和选项 1 一样好,屏幕触摸是真实的。
最后一个选项大约需要 5 分钟(至少)来准备,然后您需要手动将创建的包放到真实设备上并在每次更改代码时安装它。
也许最好的方法是使用模拟器快速测试和调试代码的小增量,然后定期使用 USB 调试模式在真实设备上确保一切仍然如预期。只有偶尔您才需要导出一个实际可部署的包。
因此,我们现在将介绍如何使用模拟器和 USB 调试在真实设备上运行应用程序。
在安卓模拟器上运行和调试应用程序
按照以下简单步骤在默认的安卓模拟器上运行应用程序:
- 从安卓工作室菜单栏中,选择工具 | AVD 管理器。AVD代表安卓虚拟设备(模拟器)。你会看到以下窗口:
图 1.10 - AVD 管理器
注意列表中有一个模拟器。在我的情况下,它是**Pixel_3a_API_30_x….**如果你在将来的某个时候跟着做,可能是一个默认安装的不同模拟器。这没关系。
重要提示
模拟器应该已经通过我们之前执行的步骤安装好了。我注意到在测试一个预发布版本时,它并没有默认安装。如果在你的虚拟设备屏幕上没有列出模拟器,选择工具 | AVD 管理器 | 创建虚拟设备… | 下一步 | R 下载 | 接受 | 下一步,然后将会下载并安装一个默认模拟器。安装完成后,点击完成,然后下一步,最后再次点击完成。现在你可以参考前面的步骤来运行模拟器。
- 点击下一张截图中显示的绿色播放图标(右侧),等待模拟器启动:
图 1.11 - 播放图标
- 现在,你可以点击安卓工作室快速启动栏上的播放图标,如下一张截图所示,如果提示,选择Pixel_3a_API_30_x…(或者你的模拟器叫什么)然后应用程序将在模拟器上启动:
图 1.12 - 安卓工作室快速启动栏上的播放图标
你完成了。这是到目前为止应用程序的外观在模拟器中。请记住,你可能(很可能)有一个不同的模拟器 - 没关系:
图 1.13 - 到目前为止应用程序的外观
显然,在我们搬到硅谷寻找资金支持之前,我们还有更多的工作要做,但这是一个很好的开始。屏幕上的消息是你好第一个片段。片段是许多安卓应用程序的构建块,我们将在整本书中进一步探讨它们。如果你点击下一步按钮,你将看到一个新的空布局,如果你然后点击上一步按钮,你将再次看到你好第一个片段屏幕。考虑到我们还没有写任何代码,这还不错。
在开发过程中,我们需要经常测试和调试我们的应用程序,以检查是否有任何错误、崩溃或其他意外情况。
注意
我们将在下一章中看到如何从我们的应用程序中获取错误和其他调试反馈。
确保它在你想要定位的每种设备类型/尺寸上看起来好并且运行正确是很重要的。显然,我们并不拥有成千上万种安卓设备中的每一种。这就是模拟器的用武之地。
然而,模拟器有时会有点慢和繁琐,尽管最近已经有了很大的改进。如果你想要真正感受到用户体验,那么你无法击败部署到真实设备。因此,在开发我们的应用程序时,我们将希望同时使用真实设备和模拟器。
提示
如果你计划很快再次使用模拟器,那么保持它运行以避免再次等待启动。
如果你想在平板上尝试你的应用程序,你将需要一个不同的模拟器。
创建一个新的模拟器
如果你想为不同的安卓设备创建一个模拟器,这很简单。从主菜单中选择工具 | AVD 管理器。在 AVD 管理器窗口中,左键单击创建虚拟设备。现在,左键单击你想创建的设备类型,电视,手机,Wear OS,或者平板。现在,简单地左键单击下一步,并按照说明创建你的新 AVD。下次运行你的应用程序时,新的 AVD 将出现作为运行应用程序的选项。我们将在下一章逐步创建一个新的平板模拟器。
现在我们可以看看如何将我们的应用程序放到真实设备上。
在真实设备上运行应用程序
首先要做的事情是访问设备制造商的网站,获取并安装设备和操作系统所需的任何驱动程序。
注意
大多数新设备不需要驱动程序。所以,你可能首先想尝试以下步骤。
接下来的几个步骤将为安卓设备进行调试设置。请注意,不同的制造商对菜单选项的结构可能略有不同。但是对于大多数设备来说,启用调试的以下顺序可能非常接近,如果不是完全相同:
-
点击设置菜单选项或手机/平板上的设置应用。
-
下一步将针对不同版本的安卓略有不同。开发者选项菜单被隐藏起来,以免困扰普通用户。你必须执行一个稍微奇怪的任务来解锁菜单选项。点击关于设备或关于手机选项。找到构建号选项,并重复点击,直到你收到一条消息,告诉你你现在是开发者了!。
注意
一些制造商有不同和晦涩的方法来完成这一步。如果这一步不起作用,可以在网上搜索你的设备和“解锁开发者选项”。
-
返回设置菜单。
-
点击开发者选项。
-
点击USB 调试的复选框。
-
将你的安卓设备连接到计算机的 USB 端口。
-
点击任何地方的安卓 Studio,让安卓 Studio 检测到你的设备已连接。你现在应该在你的设备上找到一个允许 USB 调试?的提示;点击允许。
-
点击安卓 Studio 工具栏上的播放图标,如下图所示:
图 1.14 - 来自安卓 Studio 工具栏的播放图标
- 在提示时,点击确定在你选择的设备上运行应用程序。
现在我们准备学习一些 Java,并将我们自己的 Java 代码添加到 Hello World 项目中,这将在下一章中介绍。
常见问题
- 那么,安卓真的不是一个操作系统,只是一个虚拟机,所有的手机和平板电脑都是真正的 Linux 机器吗?
不,安卓设备的所有不同子系统,包括 Linux、ART、库和驱动程序,共同构成了安卓操作系统。
- 我仍然不理解所有这些技术术语,比如 ART、面向对象、APK 等等。我应该重新阅读这一章吗?
不,这并不是必要的,因为我们只是需要介绍这个行话,随着书的进展,我们将重新讨论它并澄清它。如果你理解了以下内容,你就可以继续阅读第二章,即《第一次接触:Java、XML 和 UI 设计师》:
我们将在安卓 Point Studio 中编写 Java 代码并创建其他资源,借助 JDK,将这些代码和资源转换为真正的安卓应用程序。
总结
到目前为止,我们已经设置了我们的安卓开发环境,创建了一个新的安卓应用,并将我们的应用部署到模拟器和真实设备上。如果你仍然有未解答的问题(你可能比章节开始时有更多的问题),不要担心,因为随着我们深入了解安卓和 Java 的世界,事情会变得更清晰。
随着章节的进展,你将建立起对所有事物如何相互关联的全面理解,成功只是一个练习和更深入了解安卓 API 的问题。
在下一章中,我们将使用可视化设计师和原始 XML 代码来编辑 UI,以及编写我们的第一个 Java 方法,并开始使用安卓 API 为我们提供的一些方法。
第二章:初次接触:Java、XML 和 UI 设计师
在这个阶段,我们已经拥有了一个可用的 Android 开发环境,并且已经构建并部署了我们的第一个应用程序。然而,很明显,从 Android Studio 生成的代码不会成为下一个畅销应用程序。我们需要探索这个自动生成的代码,以便开始理解 Android,然后学习如何在这个有用的模板上进行构建。为了达到这个目的,在本章中,我们将做以下事情:
-
查看如何从我们的应用程序中获得技术反馈
-
检查我们第一个应用程序的 Java 代码和 UI XML 代码
-
让我们初次体验使用 Android Studio 的用户界面(UI)设计师。
-
学习一些核心的 Java 基础知识以及它们与 Android 的关系
-
编写我们的第一个 Java 代码
首先,让我们看看如何从我们的应用程序中获得反馈。
技术要求
您可以在 GitHub 上找到本章的代码github.com/PacktPublishing/Android-Programming-for-Beginners-Third-Edition/tree/main/chapter%2002。
检查 logcat 输出
在上一章中,我们提到我们的应用程序在模拟器或真实设备上以调试模式运行,因此当出现问题时,我们可以监视它并获得反馈。那么,所有这些反馈在哪里呢?
您可能已经注意到在 Android Studio 窗口底部有一大堆滚动文本。如果没有,请单击Logcat选项卡,如下图中标记为1的突出显示区域所示:
注意
模拟器必须在运行中,或者必须连接一个真实设备以调试模式运行,才能看到以下窗口。此外,如果由于某种原因重新启动了 Android Studio,并且自重新启动以来尚未执行应用程序,则Logcat窗口将为空。请参考第一章,在模拟器或真实设备上运行应用程序。
图 2.1 - Logcat 标签
如果您想要看到更多内容,可以将窗口拖动得更高,就像您可以在大多数其他 Windows 应用程序中一样。
这个窗口被称为logcat,有时也被称为控制台。这是我们的应用程序告诉我们用户看不到的事情发生了什么的方式。如果应用程序崩溃或出现错误,原因或原因的线索将出现在这里。如果我们需要输出调试信息,我们也可以在这里做。
注意
我们正在构建的应用程序在这个阶段不应该有任何问题,但是在将来,如果您无法弄清楚您的应用程序为什么崩溃,从 logcat 中复制并粘贴一些文本到 Google 中通常会揭示原因。
过滤 logcat 输出
您可能已经注意到,logcat 的大部分内容,如果不是全部,几乎是难以理解的。没关系。目前,我们只对错误感兴趣,这些错误将以红色突出显示,以及我们将在下一步中学习的调试信息。因此,为了在 logcat 窗口中看到更少不需要的文本,我们可以打开一些过滤器以使事情更清晰。
在上一张图中,我突出显示了另外两个区域,标记为2和3。区域2是一个下拉列表,用于控制第一个过滤器。现在左键单击它,并将其从Verbose更改为Info。我们已经大大减少了文本输出。当我们对应用程序进行了一些更改并重新部署后,我们将看到这对我们有多有用。在我们探索了构成我们项目的代码和资产之后,我们将这样做。此外,请在标记为3的区域中仔细检查,看看是否写着仅显示所选应用程序。如果没有,现在左键单击它并将其更改为仅显示所选应用程序。
现在我们可以看看 Android Studio 自动生成的内容,然后开始更改和添加代码,以使其个性化超出我们从项目创建阶段获得的内容。
探索项目 Java 和主布局 XML
我们将查看包含定义我们简单 UI 布局的代码和包含我们 Java 代码的资源文件。在这个阶段,我们不会试图理解所有这些,因为在理解之前我们需要学习更多的基础知识。然而,我们将看到这两个文件的基本内容和结构,以便我们可以将它们的内容与我们已经了解的 Android 资源和 Java 相协调。
检查 MainActivity.java 文件
首先让我们看看 Java 代码。如果出于某种原因,这些代码目前不可见,您可以通过左键单击MainActivity.java标签来查看这些代码,如下图所示:
图 2.2 - MainActivity.java 标签
由于我们不会深入研究代码的细节,带注释的截图比以文本形式重现实际代码更有用。在阅读本节时,请经常参考下一张图:
图 2.3 - Java 代码
首先要注意的是,我在代码中添加了一些空行,以便稍微间隔一下,并呈现更清晰的图像。
在 Android Studio 中折叠(隐藏)代码
现在看看图的左侧,标有多个部分的9。这指向编辑器中所有小的+和-按钮,这些按钮可以折叠和展开代码的部分。我确实折叠了一些代码的部分,而其他部分我留了出来。因此,您屏幕上看到的内容与您在图中看到的内容略有不同。在 Android Studio 中,尝试一段时间使用+和-按钮来练习隐藏和显示代码的部分。您可能希望使您的屏幕看起来像图中的样子,但这并不是继续的要求。像这样隐藏代码的技术术语是折叠。
包声明
部分package。每个 Java 文件顶部都会有一个包声明。
导入类
部分import。在import后面,我们可以看到有各种点分隔的单词。每行的最后一个单词是该行导入到我们项目中的类的名称,而每行中较早的单词是包含这些类的包和子包。
例如,下一行从androidx.appcompat.app包和子包中导入AppCompatActivity类:
import androidx.appcompat.app.AppCompatActivity;
注意
行尾的分号告诉编译器这是代码行的结束。
这意味着在这个文件中,我们将可以访问这些类。实际上,正是这些类被自动生成的代码用来制作我们在上一章中看到的简单应用程序。
在本章中,我们不会讨论所有这些类。现在重要的是我们可以导入这些类的概念。请注意,我们可以随时从任何包中添加额外的类,我们将在不久的将来改进我们的应用程序时这样做。
这个类
我们的代码的第 3部分称为类声明。以下是完整的一行;我已经突出显示了其中的一部分:
public class MainActivity extends AppCompatActivity {
类声明是一个类的开始。请注意高亮显示的部分,MainActivity。这是 Android Studio 在我们创建项目时给出的类名,也是我们之前讨论过的 Java 类的MainActivity.java文件名相同。
类和文件可以重命名,但由于这是我们应用程序的关键/主要活动,MainActivity似乎是合适的。extends关键字意味着我们的名为MainActivity的类将是AppCompatActivity类型。
我们可以使用一些类而不需要这个extends部分。我们在这里使用extends是因为我们想要使用AppCompatActivity类中的所有代码,并且还要添加我们自己的代码。所以,我们扩展它。所有这些以及更多内容将在第十章**,面向对象编程中变得更加清晰。
最后,对于{部分。现在看图的底部}部分表示类的结束。在MainActivity类的左花括号和右花括号之间的所有内容都是MainActivity类的一部分。
类内的方法
现在看一下代码的第五部分。这是完整的代码行,其中我们讨论的关键部分已经突出显示:
protected void onCreate(Bundle savedInstanceState) {
这是一个onCreate方法,是方法的名称。我们通过使用方法的名称使方法执行其代码。当我们这样做时,我们说我们正在调用一个方法。
尽管我们现在不关心方法名称两侧代码的细节,但你可能已经注意到Bundle,这是我们在import行导入的类之一,如果没有导入Bundle,Android Studio 将不知道Bundle是什么,它将无法使用,并且会以红色下划线表示为错误。
然后我们的代码将无法编译和运行。请注意前一行代码中的最后一件事是一个左花括号{。这表示onCreate方法中包含的代码的开始。现在跳到}部分。你可能已经猜到这是方法的结束。在onCreate方法的左花括号和右花括号之间的所有内容都是在调用该方法时执行的代码。
我们现在不需要深入了解这段代码的作用,但是总体上,它通过引用一个资源文件来设置应用程序的外观/布局,这个资源文件是在我们创建项目时由 Android Studio 自动生成的。我在前面的图中用轮廓标出了资源文件。
onCreateOptionsMenu和onOptionsItemSelected部分。
我们已经了解了足够的 Java 代码,可以取得一些进展。我们将在本章后面再次看到这段代码并进行更改。
到目前为止 Java 代码的总结
事实上,在我们刚刚概述的代码中包含了一些复杂的语法。然而,我们正在建立对这段代码的足够了解,以便开始快速学习 Java 和 Android,而不必先学习数百页的 Java 理论。到本书结束时,所有的代码都会有意义,但为了现在快速进展,我们只需要接受一些细节将在更长一段时间内保持神秘。
检查应用程序布局文件
现在我们将只看其中一个.xml文件。在整本书的过程中,我们将遇到几种不同的布局文件,但让我们从最容易识别的一个开始,它决定了我们应用程序的大部分外观。
在项目资源管理器窗口中,左键单击fragment_first.xml文件。文件的 XML 代码内容现在显示在 Android Studio 的主窗口中。
我们可以忽略res generated文件夹。
我们很快会探索这个 XML 代码,但首先找到并左键单击Design按钮(如下所示)切换到设计视图:
图 2.4 - 打开设计视图
现在我们可以看到设计视图,它显示了当应用程序在模拟器中运行时 XML 代码将导致显示的内容:
图 2.5 - 应用程序显示
前面的图应该看起来很熟悉,因为它显示了我们在上一章末运行的第一个应用程序的布局 - 与fragment_first.xml文件位于同一文件夹中的fragment_second.xml文件,你会看到我们在上一章中看到的第二个布局,上面有Previous按钮。实际上,与我们最初预期的相比,与布局相关的文件甚至更多,但我们将在本章和下一章中讨论它们。
本书中我们设计应用程序时所做的大部分工作都是在设计视图中完成的。然而,了解幕后发生的事情是很重要的。
设计视图是fragment_first.xml文件中包含的 XML 代码的图形表示。点击Design标签旁边的Code标签(在上一张图中)可以看到构成布局的 XML 代码。我已经注释了 XML 文本的屏幕截图,所以我们可以接下来讨论它:
图 2.6 - XML 文本的屏幕截图
首先要注意的是,这个文件并不代表整个布局。但它确实代表了大部分的表面积以及整个Hello first fragment消息和Next按钮。此外,在左侧,我们可以看到现在熟悉的+和-图标,以便我们可以折叠和展开代码的部分。
UI 布局元素
如果我们首先看一下标记为…ConstraintLayout...的代码部分。现在,ConstraintLayout是一个用来包裹 UI 其他部分的 UI 元素。
在 Android 中,当我们向 UI 添加一个新元素时,我们总是以<开头,后面跟着元素的名称。
紧随那条看起来相当长而繁琐的代码的是定义了layout_width和layout_height。所有这些属性定义了ConstraintLayout元素在用户屏幕上的显示方式。ConstraintLayout元素的属性在第一个标记为1b的>结束。
如果我们看一下我们的 XML 截图底部,我们会看到一些标记为</…ConstraintLayout>的代码,标志着ConstraintLayout元素的结束。在元素的属性的结束>和</…ConstraintLayout>之间的任何内容都被视为元素的子元素。因此,我们可以看到我们的ConstraintLayout有/包含两个子元素。现在让我们来看看这些子元素。
UI 文本元素
利用我们刚学到的知识,我们可以说 UI 元素从位置<开始,其名称为<TextView...。如果我们进一步查看我们的TextView元素,我们会发现它有几个属性。它有一个text属性,设置为"Hello first fragment"。当然,这就是我们的应用程序向用户显示的确切文本。它还有layout_width和layout_height属性,都设置为"wrap_content"。这告诉TextView它可以占用所需的内容空间。正如我们将在整本书中看到的,对于这个和其他 UI 元素,还有许多其他属性可用。TextView中的最后一个属性是id,我们将在下一节中看到我们和 Android 如何使用id属性来改进这个第一个应用程序。
注意到/>的代码。这标志着TextView元素的结束。这与ConstraintLayout元素的结束方式略有不同。当 XML 中的元素没有子元素时,我们可以像这样结束它:/>。当元素有子元素,并且其结束位置在代码中的属性定义之后时,通过重复其名称来结束元素会更清晰,像这样:</…ConstraintLayout>。
注意
你可能会想知道为什么TextView的元素名称清晰简洁(只是TextView),而ConstraintView的完整名称前面有复杂的表面混乱(androidx.constraintlayout.widget.ConstraintLayout)。这个ConstraintLayout元素是一个特殊的布局,用来确保我们的应用程序与较旧版本的 Android 兼容。正如我们将在一分钟内看到的,当我们向应用程序添加按钮时,大多数元素都有简单而简洁的名称。
UI 按钮元素
现在我们应该能够快速识别从<开始的代码及其名称:<Button...。如果我们进一步查看我们的Button,我们会发现它有几个属性。它有一个文本属性,设置为"Next"。当然,这是用户可以点击的按钮上显示的确切文本。它还有layout_width和layout_height属性,都设置为"wrap_content"。这与TextView元素一样,使得屏幕上的按钮占据所需的内容空间。Button中的最后一个属性是id,对于按钮来说,这通常是一个至关重要的属性,甚至比 UI 的其他部分更重要。由于id属性可以将此按钮与其他按钮区分开,我们可以根据id属性中保存的值为不同的按钮编写不同的功能。我们很快就会看到这个原则在实际中的应用。
注意/>处的代码。正如我们所知,这标志着Button元素的结束。
我们将在下一节中编辑并添加到这个 XML 代码,并了解更多关于属性的知识。
注意
布局的元素通常被称为小部件。
将按钮添加到主布局文件
在这里,我们将在屏幕上添加一对按钮小部件,然后我们将看到一种快速的方法来使它们真正做些什么。我们将以两种不同的方式添加按钮,首先使用可视化设计师,其次是通过直接添加和编辑 XML 代码。
通过可视化设计师添加按钮
要开始添加我们的第一个按钮,打开fragment_first.xml文件编辑器,并通过单击Design选项卡(如下所示)切换回设计视图:
图 2.7 – 设计选项卡
请注意布局左侧有一个名为Palette的窗口,如下所示:
图 2.8 – 调色板窗口
调色板分为两部分。左侧列表显示了 UI 元素的类别,并允许您选择一个类别,右侧显示了当前选定类别中所有可用的 UI 元素。
确保选择Common类别,如前图所示。现在,左键单击并按住Button小部件,然后将其拖放到布局的顶部中间附近。
如果不是很准确也没关系。然而,练习做对是很好的。因此,如果您对按钮的位置不满意,可以在布局上左键单击它,然后在键盘上按Delete键将其删除。现在您可以重复上一步,直到您有一个新的整齐放置的按钮,您对此感到满意,如下所示:
图 2.9 – 更新布局
此时,我们可以在模拟器或真实设备上运行应用程序,按钮会出现 - 有点。如果我们点击它,甚至会有一个简单的动画来表示按钮被按下和释放。如果您愿意,现在可以自由尝试一下。如果这样做,您会注意到按钮的位置不如您所期望的那样:
图 2.10 – 按钮位置不正确
现在不要担心这个明显的异常;我们将在接下来的几节中进行研究。
接下来,我们将编辑按钮的属性在Attributes窗口中。
编辑按钮的属性
通过左键单击按钮来确保按钮被选中。现在找到编辑窗口右侧的Attributes窗口,如下所示:
图 2.11 – 属性窗口
在前一个图中,你可以看到我们可以访问当前选定的 UI 元素的各种属性。要显示更多属性,我们点击不同类别的属性,并使用右侧的滚动条滚动。如果它们默认情况下尚未打开,请左键单击常用属性和所有属性部分的箭头以显示它们的选项。
现在你可以看到按钮的全部细节,我们可以开始编辑它。一个简单的按钮具有如此多的属性可能会让人感到惊讶。这表明了 Android API 为 UI 操作提供的多功能性和强大性。
正如你所看到的,我们可以在 UI 设计师中编辑大量不同的属性。在第十三章**,匿名类-让 Android 小部件活起来中,我们还将使用我们的 Java 代码编辑和操作这些属性。
现在,我们将只编辑一个属性。滚动属性窗口,直到在常用属性部分看到onClick属性,然后左键单击它以进行编辑,如下所示:
图 2.12-常用属性部分
注意
如果你在查找属性时遇到困难,你可以在所有属性部分找到它,属性按字母顺序排列。因此,onClick属性也可以在所有属性部分的冗长列表的下面三分之二处找到。
在t处键入topClick,并大写C。
当你完成时,属性窗口将如下所示:
图 2.13-onClick 选项
我们在这里做的是,在我们的代码中命名我们希望在用户点击此按钮时调用的 Java 方法。名称是任意的,但由于此按钮位于屏幕顶部,名称似乎有意义且易于记忆。我们使用的奇怪大小写是一种约定,将帮助我们保持代码清晰易读。随着代码变得越来越长和复杂,我们将看到这种约定的好处。
当然,topClick方法还不存在。Android Studio 非常有帮助,但有些事情我们需要自己做。在我们向 UI 添加另一个按钮之后,我们将使用 Java 代码编写此方法。此时你可以运行应用程序,它仍然可以工作。但是如果你点击按钮,它将崩溃,并且会出现错误,因为该方法不存在。Android Studio 通过用红色轮廓勾画onClick属性来预警我们即将发生的崩溃,如前图所示。如果你将鼠标悬停在这个红色轮廓上,你将看到问题的细节:对应的方法处理程序...未找到。
检查新按钮的 XML 代码
在为此项目添加最后一个按钮之前。点击Code选项卡,切换回查看制作 UI 的 XML 代码。
请注意,我们之前检查过的 XML 中有一个新的代码块。这是新代码块的图像:
图 2.14-XML 中的新代码块
还要注意以下细节,这些细节应该与我们对 XML 和 Android UI 元素的了解相对应:
-
新代码以
<Button开头,以/>结尾。 -
代码具有一系列属性,定义了按钮,包括
layoutWidth和layoutHeight。 -
代码包括我们刚刚添加的
onClick属性,其值为"topClick"。 -
onClick属性的topClick值被下划线标记为红色,显示缺少方法错误。 -
表示按钮的代码的开始和结束都包含在
ConstraintLayout元素中。
在设计视图中,你可以将鼠标悬停在红色下划线的topClick代码上,以显示问题的详细信息:找不到对应的方法处理程序...。
注意
在撰写本书期间,Android Studio 更新了它显示 XML 中错误的方式。目前,它用红色突出显示错误,而不是像图中和描述中所示的红色下划线。下划线在黑白打印中更清晰,所以它们被保留了。
我们可以看到问题是 Android Studio 期望在我们的 Java 代码中实现一个名为topClick的方法。一旦我们添加了第二个按钮,我们就会这样做。
通过编辑 XML 代码添加按钮
仅仅为了多样性和证明我们可以,我们现在将添加另一个按钮,只使用 XML 代码,而不是 UI 设计工具。大多数时候,我们会使用 UI 设计工具,但这个快速练习应该巩固你对 UI 设计工具和底层 XML 代码之间关系的理解。
我们将通过复制和粘贴现有按钮的代码来实现这一点。然后我们将对粘贴的代码进行一些小的编辑。
在按钮代码开始的<Button之前左键单击。注意代码的开始和结束现在有了轻微的高亮:
图 2.15 - 按钮代码
这已经确定了我们要复制的代码部分。现在左键单击并拖动以选择所有按钮代码,包括高亮显示的开始和结束,如下图所示:
图 2.16 - 选择所有按钮代码
按下Ctrl + C键盘组合键复制高亮显示的文本。将键盘光标放在现有按钮代码下方,并按Enter键几次留下一些空行。
按下Ctrl + V键盘组合键粘贴按钮代码。此时,我们有两个按钮。然而,有一些问题:
图 2.17 - 附加错误
我们在代表我们的按钮的两个代码块中都有一个额外的错误。id属性(在两个代码块中)被用红色下划线标出。这个错误的原因是两个按钮都有相同的id属性。id属性应该区分一个 UI 元素和所有其他 UI 元素。让我们来修复它。
给按钮分配唯一的 id 属性
我们可以通过调用第二个按钮button2来解决问题,但更有意义的是改变它们两个。编辑第一个按钮的代码,给它一个 ID 为buttonTop。要做到这一点,找到以下代码行(在第一个按钮中):
android:id="@+id/button"
将其更改为:
android:id="@+id/buttonTop"
注意
注意button中的小写b和Top中的大写T。
现在在第二个按钮中找到这行代码:
android:id="@+id/button"
将其更改为:
android:id="@+id/buttonBottom"
id属性行上的错误已经消失。此时,你可能会认为我们可以继续解决我们缺少的方法问题了。
然而,如果你运行应用程序并快速浏览一下,你会发现我们似乎只有一个按钮。不仅如此,(如前所述)按钮的位置也不是我们期望的:
图 2.18 - 单个按钮
原因是我们没有明确地定位它们,所以它们默认为左上角。我们在设计选项卡上看到的位置只是设计时的位置。让我们现在改变它。
在布局中定位这两个按钮
我们只能看到一个按钮的原因是两个按钮都在同一个位置。第二个按钮正好覆盖了第一个按钮。即使在设计选项卡中(随时可以查看),按钮仍然叠在一起,尽管它们位于屏幕中间。
注意
您可能想知道为什么 UI 布局工具以这种显然反直觉的方式设计。原因是灵活性。正如我们将在接下来的两章中看到的,不仅可以在设计时以不同的方式定位 UI 元素,而且还有许多不同的布局方案供应用设计者(也就是您)选择以适应他们的计划。这种灵活性在学习 Android 时会有些尴尬,但一旦您克服了这种尴尬,就会获得很大的设计能力。不要担心:我们会一步一步地进行,直到您掌握了这个技巧。
我们将让 Android Studio 自动为我们解决问题,首先通过添加到我们的代码,然后使用 UI 设计工具。首先,让我们正确设置设计时布局。在第二个按钮的代码中,找到这行代码:
tools:layout_editor_absoluteY="30dp" />
将其编辑为与此相同:
tools:layout_editor_absoluteY="100dp" />
这个微妙的变化会使第二个按钮下移一点,但只在设计时。如果您在设计选项卡中查看,按钮将整齐地定位在第一个按钮的下方,但如果您在模拟器上运行应用程序,它们仍然都位于左上角并且彼此重叠。
注意
很可能,甚至是肯定的,您的布局中dp的精确测量值会与书中所示的略有不同。只要第二个按钮的layout_editor_absoluteY属性比第一个大约70dp,那么一切都会整洁有序。在代码和设计选项卡之间切换时,随意调整这两个按钮上的此属性,直到按钮被定位到您喜欢的位置。
当您对按钮的位置满意时,切换到设计选项卡,找到推断约束按钮,如下所示:
图 2.19 - 推断约束按钮
点击推断约束按钮。Android Studio 将编辑 XML。让我们简要看一下幕后发生了什么。从两个按钮的末尾,以下代码行被移除。
如果约束没有被应用,点击清除所有约束按钮,它位于推断约束的左侧;有时候 Android Studio 会混淆并需要重置现有的约束才能推断其余的:
tools:layout_editor_absoluteX="147dp"
tools:layout_editor_absoluteY="30dp" />
这两行代码是水平(…absoluteX)和垂直(…absoluteY)定位按钮的位置。
Android Studio 还为第一个按钮添加了四行代码,为第二个按钮添加了三行。以下是在第一个按钮开头附近添加的代码:
android:layout_marginTop="30dp"
这段代码导致按钮在顶部有 30 的边距。但是相对于什么来说的顶部?看看添加到第一个按钮末尾的这三行代码:
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
注意layout_constraintEnd_toEndOf,layout_constraintStart_toStartOf和layout_constraintTop_toTopOf的新属性。分配给这些属性的值是"parent"。这会导致第一个按钮相对于parent UI 元素定位。父元素是包含布局:ConstraintLayout元素。
现在看看添加到第二(底部)按钮的三行代码。
在代码的开头附近,我们看到了这个:
android:layout_marginTop="22dp"
在第二个按钮的代码末尾,我们看到了这两行额外的代码:
app:layout_constraintStart_toStartOf="@+id/buttonTop"
app:layout_constraintTop_toBottomOf="@+id/buttonTop" />
这意味着第二个按钮相对于buttonTop小部件有 22 的边距。
注意
dp代码是一个测量/距离单位,将在*第五章**中更深入地讨论,使用 CardView 和 ScrollView 创建美丽的布局。dp测量的精确值可能会在您的布局上略有不同。
现在运行应用程序,您会看到我们有两个不同的按钮。一个具有buttonTop的id属性,它位于另一个按钮的上方,具有buttonBottom的id属性:
图 2.20 - 两个按钮选项
显然,布局还有更多内容,但到目前为止,我已经提到了其中一种我们可以设计应用程序 UI 的选项。我们将更仔细地研究ConstraintLayout布局元素,以及在第四章**,开始使用布局和 Material Design中探索更多的布局选项。
我们想在我们的 XML 代码中再做一些更改。
使按钮调用不同的方法
切换回到buttonBottom按钮:
android:onClick="topClick"
编辑代码如下:
android:onClick="bottomClick"
现在我们有两个按钮,一个在另一个上面。顶部按钮具有buttonTop的id属性和值为topClick的onClick属性。另一个具有buttonBottom的id属性和值为bottomClick的onClick属性。
现在,这些最后的 XML 代码更改意味着我们需要在我们的 Java 代码中编写两个方法(topClick和bottomClick)。
注意
当点击两个按钮调用相同的方法是可以的;这不是语法错误。然而,大多数按钮确实有不同的目的,因此如果我们的按钮执行不同的操作,这个练习将更有意义。
我们很快就会做到这一点,但在我们这样做之前,让我们更多地了解一下 Java 注释,并查看一些我们可以编写的 Java 代码来发送消息。我们将学会向用户发送消息以保持他们的知情和向自己发送消息以进行调试。
在我们的 Java 代码中留下注释
在编程中,写笔记,即代码注释,并在代码中大量使用它们总是一个聪明的主意。这是为了提醒我们在编写代码时的想法。要做到这一点,您只需附加双斜杠,然后输入您的注释,如下所示:
// This is a comment and it could be useful
此外,我们可以使用注释来注释掉一行代码。假设我们有一行代码,我们暂时想要禁用它。我们可以通过添加两个斜杠来实现,就像这样:
// The code below used to send a message
// Log.i("info","our message here");
// But now it doesn't do anything
// And I am getting ahead of where I should be
注意
使用注释注释掉代码应该只是一个临时措施。一旦找到正确的代码使用,注释掉的代码应该被删除,以保持代码文件的清洁和有组织。
让我们看看在 Android 中发送消息的两种不同方式,然后我们可以编写一些方法,当我们的新 UI 按钮被按下时发送消息。
编写消息给用户和开发人员
在本章的介绍和上一章中,我们谈到了使用其他人的代码,特别是通过 Android API 的类和它们的方法。我们看到我们可以用微不足道的代码做一些相当复杂的事情(比如与卫星通信)。
让我们开始,我们将使用 Android API 中的两个不同类来输出消息。第一个类Log允许我们将消息输出到 Logcat 窗口。第二个类Toast不是一种美味的早餐,而是会为我们的应用用户产生一个类似吐司的弹出消息。
以下是我们需要编写的代码,以向 Logcat 窗口发送消息:
Log.i("info","our message here");
为什么这样能够工作将在第十章**,面向对象编程中变得更加清晰,但现在,我们只需要知道放在两组引号之间的任何内容都将输出到 Logcat 窗口。我们很快将看到在哪里编写这种类型的代码。
以下是我们需要编写的代码,以向用户屏幕发送消息:
Toast.makeText(this, "our message",
Toast.LENGTH_SHORT).show();
这是一行非常复杂的代码,它的工作原理将在第十章**,面向对象编程中变得更加清晰。这里重要的是,我们放在引号中的任何内容都将出现在我们的用户的弹出消息中。
让我们把一些代码,就像我们刚刚看到的那样,放到我们的应用程序中。
编写我们的第一个 Java 代码
所以,我们现在知道了将输出到 Logcat 或用户屏幕的代码。但是在哪里写这段代码呢?要回答这个问题,我们需要理解 MainActivity.java 中的 onCreate 方法在应用准备展示给用户时执行。因此,如果我们将我们的代码放在这个方法的末尾,它将在用户看到应用时执行。听起来不错。
注意
我们知道要执行方法中的代码,我们需要调用它。我们已经将我们的按钮连接起来调用了一些方法:topClick 和 bottomClick。很快我们将编写这些方法。但是谁或什么在调用 onCreate 呢?这个谜团的答案是,Android 操作系统本身调用 onCreate。当用户点击应用图标运行应用时,它会这样做。在第六章**,Android 生命周期中,我们将更深入地研究这一现象,清楚地了解代码何时执行。你现在不需要完全理解这一点。我只是想给你一个概述。
让我们快速尝试一下。在 Android Studio 中切换到 MainActivity.java 标签。
我们知道 onCreate 方法在应用启动之前被调用。让我们将一些代码复制粘贴到我们应用的 onCreate 方法中,看看当我们运行它时会发生什么。
将消息代码添加到 onCreate 方法
找到 onCreate 方法的结束大括号 },并添加下面显示的高亮代码。在代码中,我没有显示 onCreate 方法的完整内容,而是使用 … 表示一些未显示的代码行。重要的是将新代码(完整显示)放在最后,但在那个结束大括号 } 之前:
@Override
protected void onCreate(Bundle savedInstanceState) {
…
…
…
// Your code goes here
Toast.makeText(this, "Can you see me?",
Toast.LENGTH_SHORT).show();
Log.i("info", "Done creating the app");
}
注意到 Android Studio 中两个 Toast 和 Log 的实例被标记为红色。它们是错误。我们知道 Toast 和 Log 是类,而类是代码的容器。
问题在于,Android Studio 在我们告诉它之前并不知道它们。我们必须为每个类添加一个 import。幸运的是,这是半自动的。
在 onCreate 方法中左键单击红色的 Toast 代码。现在按住 Alt 键,然后点击 Enter。在提示时,选择 Log。Android Studio 将在代码顶部添加 import 指令,与我们的其他导入一起,错误消失了。
注意
Alt + Enter 只是众多有用的键盘快捷键之一。以下链接是 Android Studio 的键盘快捷键参考。更具体地说,它是基于 IntelliJ Idea IDE 的。查看并收藏这个网页;在本书的过程中它将非常有价值:www.jetbrains.com/idea/docs/IntelliJIDEA_ReferenceCard.pdf。
滚动到 MainActivity.java 的顶部,查看添加的 import 指令。这里是为了方便你的:
import android.util.Log;
import android.widget.Toast;
以通常的方式运行应用程序,并查看 Logcat 窗口中的输出。
检查输出
下一张图显示了 Logcat 窗口中输出的屏幕截图:
图 2.21 – Logcat 窗口中的输出
查看 Logcat 窗口,你可以看到我们的消息 Done creating the app 被输出了,尽管它混在我们目前不感兴趣的其他系统消息中。当应用首次启动时,观察模拟器,你也会看到用户将看到的漂亮的弹出消息:
图 2.22 – 弹出消息
你可能会想知道为什么消息在那个时候被输出。答案是 onCreate 方法在应用开始响应用户之前被调用。因此,这是 Android 开发人员常见的做法,将代码放在这个方法中,为他们的应用做好准备。
现在我们将进一步编写我们自己的方法,这些方法将由 UI 中的两个按钮调用。我们将在这些新方法中放置类似的Log和Toast消息。
编写我们自己的 Java 方法
让我们直接开始编写我们的第一个 Java 方法,其中包含更多的Log和Toast消息。
注意
现在是一个好时机,如果你还没有的话,可以获取包含所有代码文件的下载包。您可以查看每个章节的完成代码。例如,本章的完成代码可以在第二章文件夹中找到。我进一步将第二章文件夹细分为java和res文件夹(用于 Java 和资源文件)。在有多个项目的章节中,我将进一步划分文件夹以包含项目名称。您应该在文本编辑器中查看这些文件。我的最爱是 Notepad++,可以从notepad-plus-plus.org/download/免费下载。在文本编辑器中查看的代码比直接从书中查看更容易阅读,尤其是平装版本,尤其是代码行很长的情况下。文本编辑器还是选择代码部分复制粘贴到 Android Studio 中的好方法。您可以在 Android Studio 中打开代码,但那样您就有可能将我的代码与 Android Studio 的自动生成代码混淆。
找到MainActivity类的结束大括号}。
注意
您要寻找整个类的结束,而不是前一节中onCreate方法的结束。花些时间来识别新代码以及它在现有代码中的位置。
在该大括号内,输入以下突出显示的代码。
@Override
protected void onCreate(Bundle savedInstanceState) {
…
…
…
…
}
…
…
…
public void topClick(View v){
Toast.makeText(this, "Top button clicked",
Toast.LENGTH_SHORT).show();
Log.i("info","The user clicked the top
button");
}
public void bottomClick(View v){
Toast.makeText(this, "Bottom button clicked",
Toast.LENGTH_SHORT).show();
Log.i("info","The user clicked the bottom
button");
}
} // This is the end of the class
注意到View这两个词可能是红色的,表示有错误。只需使用Alt + Enter键组合导入View类并删除错误。
注意
我之所以说这里“可能”会有错误,是因为这取决于您输入代码的方式。如果您复制并粘贴了代码,那么 Android Studio 可能会自动添加View类导入代码。如果您输入了新代码,那么错误将出现,并且您需要使用Alt + Enter键解决方案。这只是 Android Studio 的一个怪癖。
以通常的方式将应用程序部署到真实设备或模拟器,并开始点击按钮,以便我们观察输出。
检查输出
最后,我们的应用程序在我们告诉它执行操作时确实执行了我们告诉它执行的操作。我们可以看到,我们在按钮的onClick属性中定义的方法名称确实在点击按钮时被调用,并且适当的消息被添加到Toast消息中显示给用户。
诚然,我们仍然不明白Toast和Log类是如何工作的,我们也不完全理解我们方法语法中的public void和(View v)部分(或者自动生成的代码的其他部分)。随着我们的进展,这将变得更清晰。如前所述,在第十章**,面向对象编程中,我们将深入探讨类的世界,在第九章**,学习 Java 方法中,我们将掌握与方法相关的其余语法。
像以前一样检查onCreate方法,以及我们自己编写的两个方法,每次点击按钮时。在下图中,您可以看到我点击了每个按钮三次:
图 2.23 - Logcat 窗口输出
现在您已经熟悉了在哪里找到Logcat窗口,以后我将以修剪后的文本形式呈现Logcat输出,因为这样更容易阅读:
The user clicked the top button
The user clicked the top button
The user clicked the top button
The user clicked the bottom button
The user clicked the bottom button
The user clicked the bottom button
在下一个图中,您可以看到顶部按钮已被点击,并调用了topClick方法,触发了弹出的Toast消息,如下所示:
图 2.24 – 弹出的 Toast 消息
在整本书中,我们将定期输出到Logcat窗口,这样我们就可以看到应用程序界面背后发生了什么。Toast 消息更多用于通知用户发生了某些事情。这可能是下载完成了,收到了新的电子邮件,或者用户可能想要被告知的其他事件。
常见问题
- 你能提醒我方法是什么吗?
方法是我们的代码的容器,可以从代码的其他部分执行(调用)。方法包含在一个类中。
- 像第一章一样,我觉得这一章很难。我需要重新阅读吗?
不,如果你成功构建了应用程序,你已经取得了足够的进步来处理下一章。你知识中的所有空白将会逐渐填补,并在书籍的进展中被光荣的领悟时刻所取代。
总结
在这一章中,我们取得了很多成就。的确,很多 XML 代码仍然晦涩难懂。没关系,因为在接下来的两章中,我们将真正掌握可视化设计工具,并更多地了解 XML,尽管我们的最终目标是尽量少使用 XML。
我们看到,当我们将按钮拖放到设计中时,XML 代码会为我们生成。此外,如果我们在属性窗口中更改属性,那么 XML 代码也会被编辑。此外,我们还看到我们可以直接在代码选项卡中输入(或者在我们的情况下,复制和粘贴)XML 代码,以在我们的 UI 上创建新按钮或编辑现有按钮。
我们不仅看到了我们的第一个 Java 代码,还写了注释来帮助我们记录我们的代码,并且甚至添加了自己的方法来将调试消息输出到 Logcat 窗口和弹出Toast消息给用户。
在下一章中,我们将全面介绍 Android Studio,确切地了解不同的事情是如何同时完成的,同时了解我们项目的资产,如文件和文件夹的结构以及我们如何管理它们。这将为我们准备好深入研究 UI 设计,包括第四章**,开始使用布局和 Material Design,以及第五章**,使用 CardView 和 ScrollView 创建美丽的布局,届时我们将为我们的应用程序构建一些重要的真实布局。
第三章:探索 Android Studio 和项目结构
在本章中,我们将创建并运行另外两个 Android 项目。这些练习的目的是更深入地探索 Android Studio 和 Android 项目的结构。
当我们构建我们的应用程序准备部署时,代码和资源文件需要打包到一个Android Package(APK)文件中。因此,所有布局文件(以及我们很快会发现的其他资源)都需要在它们正确的结构中。
幸运的是,当我们从模板创建项目时,Android Studio 会为我们处理这个问题。但是,我们仍然需要知道如何找到和修改这些文件,如何添加我们自己的(有时删除)由 Android Studio 创建的文件,以及资源文件如何相互链接,有时与彼此相互链接,有时与 Java 代码(自动生成和我们自己的)相互链接。
除了了解我们项目的组成,确保我们充分利用模拟器也是有益的。
注意
模拟器在您想要确保您的应用程序在您不拥有的硬件上运行时特别有用。此外,了解一些最新功能(正如我们将在本书中了解的那样)通常需要最新的手机,模拟器是一种经济有效的方式,可以跟随所有小应用程序而不必购买最新的手机。
在本章中,我们将研究以下主题:
-
探索空活动项目模板的文件和文件夹结构
-
探索基本活动项目模板的文件和文件夹结构
-
查看空活动和基本活动模板之间的差异
-
探索 Android 模拟器
本章将使我们能够在下一章中构建和部署多个不同的用户界面(UI)设计。
技术要求
您可以在 GitHub 上找到本章的代码,网址为github.com/PacktPublishing/Android-Programming-for-Beginners-Third-Edition/tree/main/chapter%2003。
项目资源管理器和项目解剖
当我们创建一个新的 Android 项目时,我们通常使用项目模板,就像我们在第一章**,开始 Android 和 Java中所做的那样。我们使用的模板决定了 Android Studio 将生成的文件的精确选择和内容。虽然所有项目之间存在很大的相似之处值得注意,但看到差异也有帮助。让我们构建两个模板项目,并检查文件、它们的内容以及它们是如何通过代码(可扩展标记语言(XML)和 Java)链接在一起的。我们首先创建一个空活动项目。
探索空活动项目模板的文件和文件夹结构
具有自动生成 UI 的最简单项目类型是空活动项目模板。UI 几乎是空的,但已准备好添加。当我们创建一个项目,即使是空的 UI,Android Studio 也会自动生成显示 UI 的 Java 代码。因此,当我们将其添加到空的 UI 时,它已准备好显示。
让我们创建一个空活动项目。这几乎与第一章**,开始 Android 和 Java中的过程相同,只有一个细微的差异,我会指出。
如果您从第二章**,首次接触:Java,XML 和 UI 设计师中打开了项目,请选择文件 | 新建 | 新项目…。或者,如果您在 Android Studio 欢迎屏幕上,请选择开始一个新的 Android Studio 项目。然后,按照以下步骤进行:
-
在选择项目模板窗口上,选择空活动。这是与我们在第一章**,开始 Android 和 Java中所做的不同之处。
-
在
空活动应用中。 -
其余的设置可以保持默认,所以只需单击完成。
Android Studio 将生成所有的代码和其他项目资源。现在,我们可以看到已经生成了什么,并将其与我们已经知道的项目资源管理器窗口中的预期相联系。
如果模拟器还没有运行,请通过选择工具 | AVD 管理器来启动它,然后在您的虚拟设备窗口中启动您的模拟器。通过单击快速启动栏中的播放按钮在模拟器上运行应用程序,就像我们之前为我们的上一个项目做了几次一样。
看看应用程序,注意它与第一个项目有些不同。它是-嗯-空的:顶部没有菜单;底部没有浮动按钮。但是,它仍然有一些文字,说Hello World!,如下面的屏幕截图所示:
图 3.1 - 你好,世界!
现在我们有了一个全新的空活动项目,让我们来探索一下 Android Studio 为我们生成的文件和文件夹。
探索一个空活动项目
现在,是时候深入了解我们应用程序的文件和文件夹了。这将节省我们很多时间和困惑,以后在书中。然而,请注意,没有必要记住所有这些文件的位置,甚至更不需要理解文件中的代码。事实上,即使在书的最后,XML 的部分内容仍然是一个谜,但这不会阻止您设计、编码和发布令人惊叹的应用程序。
在下面的屏幕截图中,看看项目资源管理器窗口,就在项目创建后:
图 3.2 - 项目资源管理器窗口
注意前一个屏幕截图中指示的两个箭头?你可能已经猜到,这些箭头允许我们展开app和Gradle Scripts文件夹。可能你的文件夹已经展开了。为什么不尝试一下箭头,多次展开和折叠它们呢?
注意
在本书的背景下,我们不需要探索Gradle Scripts文件夹。Gradle 是 Android Studio 的重要组成部分,但其作用是向用户隐藏 Android Studio 执行的相当复杂的过程,例如添加资源文件,编译和构建项目等。因此,我们不需要进一步深入研究这一点。然而,如果您决定将 Android 提升到下一个水平,那么深入了解 Gradle 及其与 Android Studio 的关系是值得投资的时间。
我们将详细探讨app文件夹。单击app文件夹旁边的箭头以展开其内容,然后我们将开始探索。第一层内容如下屏幕截图所示:
图 3.3 - 探索 app 文件夹
我们已经展示了另外四个文件夹:manifests、java、java(generated)和res。让我们从顶部开始查看所有四个文件夹。
注意
Packt 为其图书使用的样式指南建议使用此字体来表示文件名和文件夹名。由于我们讨论的文件和文件夹既是文件又是文件夹,并且出现在屏幕上,为了保持一致性并且更加紧凑,我选择只使用后者的字体,并且在整本书中在选择不明确的情况下都会使用这个选项。
清单文件夹
manifests文件夹里只有一个文件。展开manifests文件夹并双击AndroidManifest.xml文件。注意文件已在编辑窗口中打开,并且已添加了一个标签,这样我们就可以轻松地在这个文件和其他文件之间切换。下一个屏幕截图显示了已添加的新标签,以及manifests文件夹中AndroidManifest.xml文件中包含的 XML 代码:
图 3.4 - 添加新标签
我们不需要理解文件中的一切,但值得指出的是,我们将偶尔在这里进行修改 - 例如,当我们需要请求用户访问其设备功能的权限时。当我们想要为沉浸式体验制作全屏应用程序时,我们还将编辑此文件,比如在第二十一章**, 线程和启动实时绘图应用程序中开始的绘图应用程序。
请注意,文件的结构类似于我们在上一章中看到的布局文件的结构 - 例如,有明确定义的以<section name开头并以</section name>结束的部分。这样的真实例子有<application和</application>,以及<activity和</activity>。
事实上,除了第一行之外,整个文件内容都包含在<manifest和</manifest>中。
就像我们输入计算的括号一样,这些开头和结尾部分必须匹配,否则文件将在我们的项目中引起错误。Android Studio 在这些结构的前面缩进(放置制表符)以使这些部分及其深度更加清晰。
这段代码的一些特定部分值得注意,所以我会指出其中的一些行。
下一行告诉 Android,我们想要在mipmap文件夹中显示给用户的图标来启动应用程序,它被称为ic_launcher:
android:icon="@mipmap/ic_launcher"
随着我们继续探索,我们将自己验证这一点。
下一行有两个值得讨论的方面。首先,它表示我们给我们的应用程序的名称;其次,该名称作为app_name包含在这里:
android:label="@string/app_name"
注意
在编程中,包括 Java 和 XML,在计算中,字符串是任何字母数字值。我们将在整本书中学到更多关于字符串的知识,从第七章开始,Java 变量、运算符和表达式。因此,我们可以猜测app_name标签的字母数字值是Empty Activity App,因为这是我们创建应用程序时称呼它的名称。
这可能听起来有点奇怪,但我们很快就会看到这个文件(及其标签),在以后的项目中,我们将向其中添加更多的标签和值。我们还将了解为什么以这种在这个阶段似乎相当复杂的方式向我们的应用程序添加文本的原因。
我们可以讨论AndroidManifest.xml文件中的每一行,但我们不需要这样做。让我们再看两行,因为它们彼此相关。下一行显示了我们的 Activity 的名称,这是在我们创建项目时 Android Studio 选择的。我在这里突出显示了 Activity 的名称,只是为了让它更加突出:
<activity android:name=".MainActivity">
接下来的这一行,出现在<activity和</activity>标签内,表示它是activity的一个属性,并显示这个 Activity 是在启动应用程序时应该运行的那个。它是LAUNCHER:
<category android:name="android.intent.category.LAUNCHER" />
这意味着我们的应用程序可以有多个 Activity。很多时候,如果您的应用程序有多个屏幕,比如主屏幕、设置屏幕等,它们是由多个Activity类的实例构建的。
关于Activity和activity的说明。在 XML 中,就像AndroidManifest文件一样,activity是小写的,但在 Java 中,Activity类有一个大写的A。这只是一种约定,不值得担心。正如我们刚才看到的,XML 中的activity具有一个name属性,其值指的是 Java Activity的一个实例。
让我们深入java文件夹。我想知道我们会在那里找到什么。
java 文件夹
对于稍微讽刺的评论,我表示歉意。当然,我们会找到所有的 Java 代码。首先,这只包括一个文件,但随着我们的项目的增长,我们将添加更多。展开java文件夹,您会发现另外三个文件夹,如下面的截图所示:
图 3.5 – 展开 java 文件夹
在本书中,我们只需要这三个文件夹中的一个——顶部的那个。这些文件夹的名称由包名称(在创建应用程序时选择)和应用程序名称组成,全部小写且没有空格(也是在创建应用程序时选择的)。
注意
有多个同名文件夹的原因是与自动化测试有关的高级原因,这超出了本书的范围。因此,你可以安全地忽略以(androidTest)和(test)结尾的文件夹。
在本书的过程中,我们感兴趣的唯一文件夹是顶部的那个,在我的屏幕上是com.gamecodeschool.emptyactivityapp。根据你选择的包名称和我们当前正在工作的应用程序的名称,文件夹名称会发生变化,但我们始终需要访问和添加或编辑其内容的是顶部的那个。
现在展开com.gamecodeschool.emptyactivityapp(或者你的文件夹名称)文件夹,查看其内容。在下一个截图中,你可以看到该文件夹只有一个文件:
图 3.6 – com.gamecodeschool.emptyactivityapp 文件夹
这个文件是MainActivity.java,尽管项目窗口中没有显示文件扩展名,但它在编辑器窗口上方的标签中显示。事实上,java/packagename.appname文件夹中的所有文件都将有一个.java扩展名。如果双击MainActivity.java文件,它将在编辑器窗口中打开,尽管我们也可以只点击编辑器窗口上方的MainActivity.java标签。随着我们添加更多的 Java 文件,知道它们的位置将会很有用。
检查MainActivity.java文件,你会发现它是我们在第一个项目中使用的 Java 文件的简化版本。它与原来的文件相同,只是方法更少,在onCreate方法中没有自动生成的代码。方法缺失是因为 UI 更简单,因此它们是不需要的,而且 Android Studio 没有生成它们。
为了参考,看一下下一个截图中MainActivity.java文件的内容。我已经在代码中勾画了一行:
图 3.7 – MainActivity.java 文件
它仍然具有在用户运行应用程序时执行的onCreate方法,但其中的代码要少得多,onCreate是唯一的方法。看一下onCreate方法中的最后一行代码——在继续探索res文件夹之前,我们将讨论这个。以下是讨论中的代码行:
setContentView(R.layout.activity_main);
代码正在调用一个名为setContentView的方法,并且正在向setContentView方法传递一些数据,以便setContentView方法中的代码可以使用。传递给setContentView的数据是R.layout.activity_main。
现在,我只想提一下setContentView方法是由 Android 提供的,R.layout.activity_main是什么?
我们将通过探索res文件夹来了解,但是快速提一下Java(生成的)文件夹,这样我们在进展中不会为此烦恼。首先要注意的是,该文件夹是在模拟器或真实设备上首次运行应用程序时自动生成的,因此如果你还没有运行应用程序,你就看不到它。
Java(生成的)文件夹
这个文件夹包含了由 Android Studio 生成的代码,我们不需要关心其中的内容。即使是需要它的高级用户通常也只是用它作为参考。
让我们继续讨论res文件夹和R.layout.activity_main代码。
res 文件夹
res文件夹是所有资源的存放地。左键单击展开res文件夹,我们将检查里面的内容。这是该文件夹内顶层文件夹的截图:
图 3.8 – res 文件夹
让我们从列表的顶部开始,看drawable文件夹。
res/drawable文件夹
这个名称有点透露了一些东西,但drawable文件夹中包含的不仅仅是图形。随着我们在书中的进展,我们确实会向这个文件夹中添加图形。但是现在,它只包含两个文件。
这些文件是ic_launcher_foreground和ic_launcher_background。我们不会检查任何文件,因为我们永远不需要修改它们,但我会简单提一下它们是什么。
如果你打开这些文件,你会发现它们非常长而且技术性很强。它们包括看起来是坐标、颜色等的列表。它们被称为图形蒙版,用于 Android 适应/遮罩其他图形—具体来说,在这种情况下,是应用程序的启动图标。这些文件向 Android 提供了关于如何调整应用程序启动图标的指令。
这个系统是为了让不同的设备制造商可以创建适合自己 Android 设备的蒙版。这些蒙版默认位于drawable文件夹中(ic_launcher_foreground和ic_launcher_background),它们是默认的自适应蒙版,为启动图标添加了视觉上令人愉悦的阴影和深度。
注意
如果自适应图标的概念对你有吸引力,那么你可以在这个链接上看到Android 开发者网站上的完整而非常直观的解释,网址为developer.android.com/guide/practices/ui_guidelines/icon_design_adaptive。你不需要查看这个页面就可以继续。
我们现在对drawable文件夹有足够的了解,让我们继续看layout文件夹。
res/layout文件夹
res文件夹是应用程序所有资源的存放处,如图标、布局(XML 文件)、声音和字符串。让我们仔细看一下。
展开layout文件夹,你会看到一个名为activity_main.xml的布局文件,如果你打开它查看内容,你会发现它与我们在上一章中编辑的文件非常相似。这次内容更少,因为我们生成了一个ConstraintLayout元素,包裹着一个写着Hello World!的TextView小部件。
一定要查看内容,但这里最有趣的不是这个。仔细看文件的名称(不包括 XML 文件扩展名):activity_main。
现在,回想一下MainActivity.java文件中的 Java 代码。这是我们说过设置 UI 的代码行。我已经突出显示了一部分代码:
setContentView(R.layout.activity_main);
R.layout.activity_main代码确实是对res/layout文件夹中的activity_main文件的引用。这是我们的 Java 代码和 XML 布局/设计之间的连接。
注意
除了activity_main.xml的内容之外,与第一个项目有所不同——在第一个项目的layout文件夹中,有多个额外的文件。在本章的后面,我们将使用第一章中使用的相同模板(基本活动)构建另一个项目,以了解原因。
在此之前,让我们探索最后两个文件夹及其所有子文件夹,从列表中的下一个开始:mipmap。
res/mipmap文件夹
mipmap文件夹很简单—嗯,相对简单。展开文件夹查看其内容,如下面的截图所示:
图 3.9 – mipmap 文件夹
在这里,我们可以看到两个子文件夹:ic_launcher和ic_launcher_round。ic_launcher的内容是我们在设备的应用程序抽屉/主屏幕中看到的常规启动图标的图形,而ic_launcher_round包含使用圆形图标的设备的图形。双击每个文件夹中的.png文件来查看。我在下一个截图中将它们并排放置,以帮助我们讨论:
图 3.10 – 启动图标
你可能也想知道为什么每个文件夹中有五个ic_launcher….png文件。这是因为为不同的屏幕尺寸和分辨率提供合适缩放的图标是一个良好的做法。通过提供带有hdpi、mdpi、xhdpi、xxhdpi和xxxhdpi资格的图像,这允许不同的 Android 设备选择最适合用户的图标。
注意
字母dpi代表高、中、超高、超超高等前缀。这些被称为限定符,随着我们的进展,我们会看到 Android 有很多限定符,帮助我们构建适合不同 Android 设备的应用程序。
mipmap文件夹的最后一个谜团是,每个子文件夹中也有一个 XML 文件。打开其中一个,你会看到它们引用了我们在drawable文件夹中看到的ic_launcher_foreground和ic_launcher_background文件。这告诉 Android 设备从哪里获取自适应图标的详细信息。这些文件不是必需的,但它们使图标看起来更好,同时增加了它们的灵活性。
我们还有一个文件夹和它的所有文件,然后我们将充分理解 Android 应用程序的结构。
res/values 文件夹
打开res/values文件夹,可以看到我们将依次简要讨论的三个文件。所有这些文件相互关联/引用,或者与我们已经看过的其他文件相互关联。
为了完整起见,这里是res/values文件夹中三个文件的截图:
图 3.11 - res/values 文件夹
注意
在values文件夹内还有一个themes文件夹,但在本书的上下文中我们不需要探索这个。
理解的关键不在于记忆连接,当然也不是试图记忆或理解文件中的代码,而是要欣赏到迄今为止我们所见过的所有文件和代码之间相互关联的本质。
让我们依次查看文件的内容。
颜色.xml 文件
接下来我们将查看colors.xml文件的内容,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#6200EE</color>
<color name="colorPrimaryDark">#3700B3</color>
<color name="colorAccent">#03DAC5</color>
</resources>
请注意,起始和结束标签采用了我们从 XML 文件中所期望的通常模式。有一个开放的<resources>标签和一个闭合的</resources>标签。作为资源的子元素,有三对<color> … </color>标签。
在每个color标签中都有一个name属性和看起来很奇怪的代码,由数字和字母组成。name属性是颜色的名称。我们将在接下来的文件中看到各种名称的引用。
代码是定义实际颜色本身的东西。因此,当引用名称时,相关代码定义的颜色将显示在屏幕上。我们将在一会儿看到这些名称在哪里被引用。
注意
代码称为0到9和a到f,共有 16 个可能的值。如果你想了解更多并尝试使用十六进制颜色,请访问www.color-hex.com/color-wheel/。如果你对十六进制(基数 16)、二进制(基数 2)等数字基感到好奇,那么请看下面的文章,它解释了它们,并谈到了为什么人类通常使用十进制:betterexplained.com/articles/numbers-and-bases/。你不需要阅读这些文章来继续阅读本书。
字符串.xml 文件
大多数现代应用程序都是为尽可能广泛的受众而制作的。此外,如果一个应用程序的规模或复杂性很大,那么软件公司中的角色通常被分成许多不同的团队 - 例如,为 Android 应用程序编写 Java 代码的人很可能与设计 UI 布局的人几乎没有关系。
通过将应用程序的内容与应用程序的编程分开,可以更容易地随时进行更改,还可以在不更改每个 Java 代码的情况下为多种不同的口头语言创建内容。
接下来看一下strings.xml文件的内容:
<resources>
<string name="app_name">Empty Activity App</string>
</resources>
我们可以看到在现在熟悉的<resources>…</resources>标签中,有一个<string>…</string>标签。在string标签中,有一个名为name的属性,具有app_name值,然后是Empty Activity App的进一步值。
让我们再看一下我们之前在清单文件夹部分中探索过的AndroidManifest.xml文件中的一行。接下来是相关的代码行,但如果您想要查看完整的上下文中的代码行,请参考 Android Studio 中的文件本身:
android:label="@string/app_name"
android:label属性被赋予了@string/app_name的值。在 Android 中,@string指的是strings.xml文件中的所有字符串。在这个特定的应用程序中,具有app_name标签的string属性具有Empty Activity App的值。
因此,在应用程序运行时,AndroidManifest.xml文件中先前显示的代码行对屏幕产生以下影响:
图 3.12 – AndroidManifest.xml 文件效果
虽然这个系统乍看起来可能有些复杂,但在实践中,它将设计和内容与编码分开,这是非常高效的。如果应用程序的设计者想要更改其名称,他们只需编辑strings.xml文件,而无需与 Java 程序员进行交互;如果应用程序中的所有文本都是作为字符串资源提供的,那么在项目进行过程中所有这些文本都可以很容易地进行更改和调整。
Android 通过允许开发人员为每种语言/区域设置不同的字符串资源文件来进一步提高了这种灵活性。这意味着开发人员可以为全球范围内的用户提供完全相同的 Java 代码。Java 程序员只需引用字符串资源的name属性,而不是将文本本身硬编码到 Java 中,然后其他部门可以设计文本内容并处理诸如语言翻译之类的任务。我们将在第十八章中使应用程序多语言化,本地化。
注意
在 Java 代码中直接硬编码实际文本而不是使用字符串资源是可能的,我们会不时这样做,为了方便展示一些 Java 而不必陷入编辑或添加到strings.xml文件中。在上一章中,当我们制作吐司消息并将文本输出到控制台时,我们就这样做了。
Android 系统允许设计者选择一系列颜色、文本、图像、声音和其他资源,轻松地为世界各地的不同地区制作其应用程序的变体。
例如,在西方文化中,绿色可以代表自然和正确性的主题;在许多中东国家,绿色代表生育力,是与伊斯兰教相关的颜色。虽然您可能在这些地区分发绿色,但您的应用程序将被认为是非常不同的。
如果您将应用程序推出到印度尼西亚,绿色在许多(尽管不是所有)印度尼西亚人中是受到文化蔑视的。接下来,您在中国推出,绿色可能会带有与不忠有关的负面含义。这是一个典型的 Java 程序员永远不会学会应对的困难局面——幸运的是,由于我们可以在 Android Studio 中分担责任的方式,他们不需要了解这一点。
颜色——因此,样式和主题——是一个非常专业的话题。虽然我们不会探索比绿色更深入的内容,但希望您能看到将编程、布局、颜色和文本内容的责任分开的好处。
值得一提的是,即使我们不会雇佣设计师、翻译员和文化专家团队,也完全有可能制作出一款受到成千上万甚至数百万用户喜爱的精彩应用。然而,即使我们不打算雇佣设计师、翻译员和文化专家团队,我们仍然必须在设计的基础上进行工作,这就是为什么我们要深入研究。
到目前为止,我们已经很好地掌握了 Android 项目的组成部分以及不同方面之间的联系。让我们再构建一个应用程序,不需要以相同的细节深入研究,而是看看不同的应用程序模板对 Android Studio 生成的基础文件造成的影响。
探索基本活动项目模板的文件和文件夹结构
使用自动生成 UI 的下一个最简单的项目类型是基本活动项目。这是我们在*第一章**《开始 Android 和 Java》*中创建的相同类型的项目。现在可以打开该项目,但是生成一个新项目同样快速,而且我们也可以在没有任何修改和添加的情况下进行检查讨论。
继续如下操作:
-
运行 Android Studio 并左键单击开始新的 Android Studio 项目选项。
-
接下来是选择项目模板窗口。选择基本活动,然后点击下一步。
-
在配置您的项目窗口中,设置项目如下:
-
点击完成按钮,我们将运行应用程序,看看我们取得了什么成就。
现在,我们可以深入研究文件。我们不会像我们为空活动项目那样详细查看所有内容;相反,我们只会看看文件之间的相互联系,并进行一些比较。
探索基本活动项目
首先让我们看看代码编辑器中MainActivity.java选项卡中的 Java 代码。正如前面所述,基本活动项目比空活动项目更复杂。
注意
您可以打开尽可能多的 Android Studio 实例。如果要并排比较项目,请选择文件 | 打开,然后选择项目,当提示时选择新建窗口以打开项目,而不关闭已经打开的任何项目。
首先要注意的是onCreate方法中有一些额外的代码。
MainActivity.java 文件
我在*第二章**《第一次接触:Java、XML 和 UI 设计师》*中非常简要地提到了 Java 代码和 XML 代码中的这些相互联系。让我们浏览一下资源文件,并指出这些 Java 代码指向的 XML 文件。
下面是下一个显示的 Java 代码。我稍微重新格式化了一下,以便在书中更易读:
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own
action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
要完全理解这段代码将需要更多的章节,但是指出这段代码使用资源文件的地方只需要一会儿,然后我们会更加了解构成我们项目的组件。
代码涉及两个资源。第一个是Toolbar资源,通过R.id.toolbar引用。第二个是FloatingActionBar资源,通过R.id.fab引用 XML 文件,我们很快就会看到。
如果我们在项目窗口中打开res/layout文件夹和java文件夹,我们会发现与空活动项目中的情况不同,如下图所示:
图 3.13 – res/layout 文件夹和 java 文件夹
现在有三个自动生成的 Java 文件和四个自动生成的 XML 布局文件。
请记住,这个应用有两个屏幕——第一个屏幕上有一个Hello first fragment消息和一个Next按钮;第二个屏幕上只有一个Previous按钮。
发生的事情是,Android Studio 不仅为每个屏幕的外观提供单独的布局文件,而且还为控制每个屏幕的代码提供单独的 Java 文件。如果你只是表面上接受了我刚才说的话,因此你会期望有两个布局文件和两个 Java 文件,但我们有更多。
正如我们已经知道的,当用户运行应用程序时,MainActivity.java文件的onCreate方法被执行。这设置了应用程序,包括布局。布局在activity_main.xml中,但这个文件不再控制两个主要屏幕的布局。它具有两个屏幕之间一致的元素,并将布局委托给content_main.xml。然后,content_main.xml文件定义了它所占据的屏幕区域,并将将出现在此区域的细节委托给另一个文件,即res/navigation文件夹中的nav_graph.xml文件。然后,nav_graph.xml文件确定使用哪个布局(fragment_first.xml或fragment_second.xml)以及哪个相应的 Java 文件将控制布局(FirstFragment.java或SecondFragment.java)。
在这个阶段,显而易见的复杂性可能会让人不知所措。我猜这可能是使得学习 Android 开发没有任何先前开发经验如此具有挑战性的原因之一。但好消息是:
-
我们不需要记住和理解所有这些相互关联的细节。
-
我们可以构建大量的应用程序而不使用其中任何部分。
-
随着我们在书中的进展,并且与这个谜题的不同部分一起工作,我们将逐渐熟悉它们。
看一下下一个图,展示了基本活动模板应用程序的工作原理:
图 3.14 – 基本活动模板
如果显而易见的复杂性看起来令人沮丧,那么了解为什么要这样做可能会有所帮助。我们已经讨论过将布局与编程分开,并进一步分离文本和图形,以允许不同的团队处理应用程序的不同方面。现在,我们可以进一步分离不仅是应用程序不同屏幕之间的导航,比如主菜单屏幕、设置屏幕和其他一些屏幕,而且与每个屏幕相关的布局和编程也是分开的,因此它们也可以由不同的团队同时进行。随着我们在章节中的进展,我们会更多地讨论这个问题。
我们将研究编写单独的片段布局和控制每个片段的单独 Java 代码,以及从第二十四章开始,我们将更深入地了解为什么我们希望这样做,并且我们将在下一章更深入地研究activity_main.xml和content_main.xml等相互关联的布局文件。
目前,让我们更深入地看一下MainActivity.java文件代码如何与activity_main.xml布局相连接。我们会发现,虽然activity_main.xml文件负责放置工具栏和浮动操作按钮,但MainActivity.java文件负责控制用户与它们交互时发生的事情。
activity_main.xml 文件
目前,打开activity_main.xml文件,你会看到有一些元素来代表toolbar和fab。引用这些元素的 Java 代码正在设置工具栏和浮动操作栏以供使用。XML 代码,正如我们所期望的那样,描述了它们的外观。
这是工具栏的 XML 代码:
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
注意它提到了工具栏、颜色和样式,以及其他一些方面。
为了清晰起见,这是实际工作应用程序中的工具栏:
图 3.15 – 应用程序的工具栏
这是悬浮操作按钮的 XML 代码。我稍微重新格式化了代码的第一行,以便在本书的打印版本中更好地显示:
<com.google.android.material.floatingactionbutton.
FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
app:srcCompat="@android:drawable/ic_dialog_email" />
请注意,它具有fab的id值。通过这个id值,我们可以在我们的 Java 代码中访问悬浮操作按钮,具体来说,是MainActivity.java中的这一行:
FloatingActionButton fab = findViewById(R.id.fab);
在这行代码执行之后,我们的 Java 代码中的fab对象现在可以直接控制悬浮操作按钮及其所有属性。在第十三章,匿名类 – 让 Android 小部件栩栩如生中,我们将学习如何详细做到这一点。
这是实际应用程序中的悬浮操作按钮:
图 3.16 – 悬浮操作按钮
我没有详细解释代码,因为在这个阶段没有意义。只需开始在这里梳理相互关系:
-
XML 文件可以引用其他 XML 文件。
-
Java 可以引用 XML 文件(以及,正如我们很快将看到的,其他 Java 文件)。
-
现在,我们已经看到在 Java 中,我们可以通过其
id属性抓取 XML 文件中特定部分的 UI 控制。
我们已经从这个文件中看到足够的内容,所以让我们继续并深入了解剩下的文件。
MainActivity.java 中的额外方法
那么,这些方法是做什么的,它们何时被调用,由谁调用?下一个区别是这个额外的方法(再次略微重新格式化以供展示):
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the
// action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
这段代码准备(膨胀)了在menu_main.xml文件中定义的菜单,就像onCreate方法一样,onCreateOptionsMenu方法是一个重写的方法,由操作系统直接调用。
然后,接下来是另一个方法:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar
will
// automatically handle clicks on the Home/Up button, so
long
// as you specify a parent activity in
AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
这个方法也被重写了,并且它也是由操作系统直接调用的。它处理用户选择菜单中的项目(选项)时发生的情况。目前,它只处理一个选项——设置选项——并且目前不执行任何操作,如下所示:
The code if (id == R.id.action_settings) {
这确定了return true代码是否执行任何选项,并且控制是否返回到被用户点击设置菜单选项中断的应用程序的任何部分执行之前。
我们现在已经知道了几乎足够的知识。不要担心记住所有这些连接。我们将回到每个连接,进行更深入的调查,并巩固我们对每个连接的理解。
现在,我们可以更仔细地看一下 Android 模拟器。
探索 Android 模拟器
随着我们的进展,熟悉如何使用 Android 模拟器会有所帮助。如果您还没有使用最新版本的 Android,甚至执行一些简单任务的方式(例如查看所有应用程序)可能与您当前的设备工作方式不同。此外,我们想知道如何使用所有模拟器附带的额外控件。
模拟器控制面板
您可能已经注意到当您运行模拟器时,旁边会出现一个迷你控制面板。让我们来看一些最有用的控件。看一下模拟器控制面板的截图。我已经在上面加了注释,以帮助讨论它:
图 3.17 – 模拟器控制面板
我将简要提及更明显的控件,并在必要时进行更深入的讨论:
-
这些是窗口控件。最小化或关闭模拟器窗口。
-
从上到下,关闭模拟器,模拟关闭实际设备的电源。接下来的两个图标分别提高和降低音量。
-
这两个按钮允许您将模拟器向左和向右旋转。这意味着您可以测试您的应用程序在所有方向下的外观,以及在应用程序运行时如何处理方向更改。这两个图标立即下方的图标分别是截图和放大。
-
这些图标模拟了返回按钮和主页按钮,以及查看正在运行的应用程序。请尝试一下这些按钮,因为我们将不时需要使用它们,包括在第六章中,Android 生命周期。
-
按下此按钮以启动高级设置菜单,在那里您可以与传感器、全球定位系统(GPS)、电池、指纹识别器等进行交互。如果您感兴趣,可以尝试一些这些设置。
让我们来玩一下模拟器本身。
将模拟器用作真实设备
模拟器可以模拟真实手机的每个功能,因此可以写一本关于使用它的整本书。如果您想要编写用户喜爱的应用程序,那么了解各种 Android 设备是值得花时间去做的。我只想在这里指出一些最基本的功能,因为没有这些基本的交互,将很难跟上本书的内容。此外,如果您有一部较旧的 Android 设备,那么一些基本的功能(如访问应用程序抽屉)已经发生了变化,您可能会感到有些困惑。
访问应用程序抽屉
将鼠标光标放在主屏幕底部并向上拖动以访问应用程序抽屉(所有应用程序)。下面的截图显示了这个动作进行到一半的情况:
图 3.18 - 向上拖动以访问应用程序抽屉
现在,您可以运行模拟器上安装的任何应用程序。请注意,当您通过 Android Studio 运行您的应用程序之一时,它将保留在模拟器上安装,并且因此可以从应用程序抽屉中运行。但是,您在 Android Studio 中对应用程序所做的每一次更改都需要您再次点击 Android Studio 快速启动栏上的播放按钮来运行/安装应用程序 - 就像我们一直在做的那样。
查看活动应用程序并在应用程序之间切换
要查看活动应用程序,您可以使用模拟器控制面板,即模拟器控制面板截图上标有数字4的方块(图 3.17)。要使用手机屏幕访问相同的选项(就像在真实设备上一样),向上滑动,就像访问应用程序抽屉时一样,但只需滑动大约屏幕长度的四分之一。这个过程在下面的截图中有所说明:
图 3.19 - 向上滑动
现在,您可以通过最近的应用程序向左和向右滑动,向上滑动应用程序以关闭它,或者点击返回按钮返回到您在查看此选项之前所做的事情。请尝试一下,因为我们经常会使用这些基本功能。
总结
请记住,本章的目标是熟悉 Android/Android 项目的系统/结构。Android 项目是 Java 和多种资源文件的交织。资源文件可以包含 XML 来描述我们的布局、文本内容、样式和颜色,以及图像。资源可以针对世界各地的不同语言和地区进行生产。我们将在本书中看到和使用的其他资源类型包括主题和音效。
不需要记住不同资源文件和 Java 文件之间的各种连接方式。重要的是要意识到它们之间的联系,并能够检查各种类型的文件,并意识到它们何时依赖于另一个文件中的代码。每当我们从 Java 代码创建与 XML 代码的连接时,我都会再次指出连接的细节。
我们不需要学习 XML 和 Java,但我们会对它有一点点了解。Java 将是本书的重点,但我们的 Java 经常会涉及 XML 代码,因此理解并看到一些互连的示例将有助于您更快地取得进展。
我们还探索了模拟器,以便在测试我们的应用程序时充分利用它。
在下一章中,我们将使用两种不同的 Android 布局方案构建两个自定义布局。我们还将编写一些 Java 代码,以便我们可以通过点击按钮来在它们之间切换。
第四章:开始使用布局和 Material Design
我们已经看到了 Android Studio 的用户界面(UI)设计师,以及 Java 的实际应用。在这个动手实践的章节中,我们将构建三个更多的布局——仍然相当简单,但比我们迄今为止所做的要进一步。
在我们开始动手之前,我们将快速介绍Material Design的概念。
我们将看到另一种称为LinearLayout的布局类型,并逐步使用它来创建可用的 UI。我们将进一步使用ConstraintLayout,既了解约束,又设计更复杂和精确的 UI 设计。最后,我们将介绍TableLayout,用于在易于阅读的表格中布置数据。
我们还将编写一些 Java 代码,以在我们的应用程序/项目中在不同的布局之间切换。这是第一个将多个主题整合到一个整洁包裹中的重要应用程序。该应用程序名为探索布局。
在本章中,我们将讨论以下主题:
-
了解 Material Design
-
探索 Android UI 设计
-
介绍布局
-
构建
LinearLayout并学习何时最好使用这种类型的布局 -
构建另一个稍微更高级的
ConstraintLayout并了解更多关于使用约束的知识 -
构建
TableLayout并填充数据以显示 -
将所有内容连接在一个名为探索布局的应用程序中
首先是 Material Design。
技术要求
您可以在 GitHub 上找到本章的代码github.com/PacktPublishing/Android-Programming-for-Beginners-Third-Edition/tree/main/chapter%2004。
了解 Material Design
您可能听说过 Material Design,但它究竟是什么?Material Design 的目标非常简单——创建美观的 UI。然而,它也是关于使这些 UI 在 Android 设备上保持一致。Material Design 并不是一个新的想法;它直接来源于纸笔设计中使用的设计原则,例如通过阴影和深度具有视觉上令人愉悦的装饰。
Material Design 使用材料层的概念,您可以将其视为照片编辑应用程序中的图层的方式。通过一组原则、规则和指南实现一致性。必须强调的是 Material Design 是完全可选的,但也必须强调的是 Material Design 是有效的——如果您不遵循它,您的设计很可能不会受到用户的欣赏。毕竟,用户已经习惯了某种类型的 UI,而该 UI 很可能是使用 Material Design 原则创建的。
Material Design 是一个值得追求的合理标准,但在学习其细节时,我们不应该让它阻碍我们学习如何开始使用 Android。
本书将专注于完成任务,偶尔指出 Material Design 如何影响设计,以及对于那些想深入了解 Material Design 的人的更多资源。
探索 Android UI 设计
我们将看到,对于 Android UI 设计,我们所学到的很多内容都是依赖上下文的。给定小部件的x属性如何影响其外观可能取决于小部件的y属性,甚至取决于另一个小部件的属性。这并不容易逐字学习。最好期望通过实践逐渐取得更好和更快的结果。
例如,如果您通过拖放小部件到设计中来玩转设计师,生成的可扩展标记语言(XML)代码将会有很大的不同,这取决于您使用的布局类型。在本章中我们将看到这一点。
这是因为不同的布局类型使用不同的方法来决定其子元素的位置,例如,我们将在下面探索的LinearLayout与我们项目中默认添加的ConstraintLayout的工作方式完全不同。
这些信息起初可能看起来是一个问题,甚至是一个坏主意,而且起初确实有点尴尬。然而,我们将会逐渐了解到,这种清晰的布局选项的丰富性及其各自的特点是一件好事,因为它们给了我们几乎无限的设计潜力。您几乎可以想象不可能实现的布局是非常少的。
然而,这几乎无限的潜力也带来了一些复杂性。开始掌握这一点的最好方法是构建一些不同类型的工作示例。在本章中,我们将看到三种类型的布局,如下所述:
-
LinearLayout -
ConstraintLayout -
TableLayout
我们将看到如何利用可视化设计工具的独特功能使事情变得更容易,我们还将对自动生成的 XML 进行一些关注,以使我们的理解更全面。
介绍布局
我们已经在第一章,开始 Android 和 Java中看到了ConstraintLayout,但除此之外还有更多的布局。布局是将其他 UI 元素组合在一起的构建块。布局也可以包含其他布局。
让我们看一下 Android 中一些常用的布局,因为了解不同的布局及其优缺点将使我们更加了解可以实现什么,从而扩展我们的可能性。
我们已经看到,一旦我们设计了一个布局,就可以在我们的 Java 代码中使用setContentView方法将其付诸实践。
让我们构建三种不同布局类型的设计,然后使用setContentView并在它们之间切换。
创建和探索布局项目
在 Android 中最困难的事情之一不仅是找出如何做某事,而是找出如何在特定上下文中做某事。这就是为什么在本书中,除了向您展示如何做一些很酷的东西之外,我们还会将许多主题链接到跨越多个主题和章节的应用程序中。探索布局项目是这种类型的第一个应用程序。我们将学习如何构建多种类型的布局,同时将它们全部链接在一个方便的应用程序中。
让我们开始吧,如下所示:
- 在 Android Studio 中创建一个新项目。如果您已经打开了一个项目,请选择文件 | 新建项目。在提示时,选择在同一窗口中打开,因为我们不需要参考以前的项目。
重要提示
如果您在 Android Studio 的起始屏幕上,可以通过单击创建新项目选项来创建一个新项目。
-
确保选择空活动项目模板,因为我们将从头开始构建大部分 UI。单击下一步按钮。
-
输入
探索布局作为应用程序名称,然后单击完成按钮。
查看MainActivity.java文件。以下是代码,不包括import…语句:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
找到对setContentView方法的调用,并删除整行代码。该行在前面的代码片段中显示为高亮显示。
这正是我们想要的,因为现在,我们可以构建我们自己的布局,探索底层的 XML,并编写我们自己的 Java 代码来显示这些布局。如果您现在运行应用程序,您将只会得到一个带有标题的空白屏幕;甚至没有一个 Hello World!的消息。
我们将要探索的第一种布局类型是LinearLayout类型。
使用 LinearLayout 构建布局
LinearLayout可能是 Android 提供的最简单的布局。顾名思义,其中的所有 UI 项都是线性布局的。你只有两个选择:垂直和水平。通过添加以下代码行(或通过LinearLayout编辑)来垂直布局:
android:orientation="vertical"
然后(你可能已经猜到了)将"vertical"更改为"horizontal"以水平布局。
在我们对LinearLayout进行任何操作之前,我们需要将其添加到布局文件中;由于我们在这个项目中构建了三个布局,所以我们还需要一个新的布局文件。
向项目添加 LinearLayout 布局类型
在项目窗口中,展开res文件夹。现在,右键单击layout文件夹,然后选择新建。注意,有一个布局资源文件选项,如下面的截图所示:
图 4.1 - 将 LinearLayout 添加到项目
选择LinearLayout,如下面的截图所示:
图 4.2 - 创建新的资源文件
在main_menu中。名称是任意的,但这个布局将是我们用来选择其他布局的主菜单,所以名称似乎是合适的。
点击 XML 文件中的LinearLayout,并将其放在layout文件夹中,准备好为我们构建新的主菜单 UI。新文件会自动在编辑器中打开,准备好让我们进行设计。
准备工作空间
点击设计选项卡以切换到设计视图,如果你还没有在这个视图中。通过拖动和调整窗口边框(就像大多数窗口化应用程序中一样),使调色板、设计和属性尽可能清晰,但不要超出必要的大小。下面的截图显示了我选择的大致窗口比例,以使设计我们的 UI 和探索 XML 尽可能清晰。截图中的细节并不重要:
图 4.3 - 准备工作空间
重要提示
我已经尽可能地将项目、调色板和属性窗口变窄,但没有遮挡任何内容。我还关闭了屏幕底部的构建/logcat 窗口,结果是我有一个很清晰的画布来构建 UI。
检查生成的 XML
点击代码选项卡,我们将查看当前阶段构成我们设计的 XML 代码的当前状态。以下是代码,以便我们讨论(我稍微重新格式化了一下,以使其在页面上更清晰):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>
我们有通常的起始和结束标签,正如我们可能已经预测到的那样,它们被称为<LinearLayout和</LinearLayout>。目前还没有子元素,但有三个属性。我们知道它们是LinearLayout的属性而不是子元素,因为它们出现在第一个闭合>之前。为了清晰起见,前面的代码中突出显示了定义这个LinearLayout的三个属性。
第一个属性是android:orientation,或者更简洁地说,我们将只提到属性而不包括android:部分。orientation属性的值为vertical。这意味着当我们开始向这个布局添加项目时,它将垂直从上到下排列它们。我们可以将vertical值更改为horizontal,它会从左到右排列。
接下来的两个属性是layout_width和layout_height。这些属性确定了LinearLayout的大小。给这两个属性的值都是match_parent。布局的父级是整个可用空间。通过水平和垂直匹配父级,布局将填充整个可用空间。
向 UI 添加一个 TextView
切换回设计选项卡,我们将向 UI 添加一些元素。
首先,在调色板中找到TextView小部件。这可以在 UI 上找到TextView,请注意它整齐地位于LinearLayout的顶部。
查看LinearLayout上的 XML,并且它缩进了一个制表符以使其清晰。以下是TextView小部件的代码,不包括LinearLayout的周围代码:
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView" />
请注意,它有四个属性:id属性,以防我们需要从另一个 UI 元素或我们的 Java 代码中引用它;layout_width属性设置为match_parent,这意味着TextView横跨整个LinearLayout的宽度;layout_height属性设置为wrap_content,这意味着TextView的高度正好足够容纳其中的文本。最后,目前它有一个text元素,确定它将显示的实际文本,目前设置为“TextView”。
切换回Design选项卡,我们将进行一些更改。
我们希望这段文字成为此屏幕的标题文字,即菜单屏幕。在搜索框中输入text,如下截图所示。找到text属性并将其值更改为Menu:
图 4.4 - 将 TextView 添加到 UI
提示
您可以通过搜索或只是浏览选项来查找任何属性。找到要编辑的属性后,左键单击选择它,然后按键盘上的Enter键使其可编辑。
接下来,使用您喜欢的搜索技术找到textSize属性,并将textSize设置为50sp。输入这个新值后,文本大小将增加。
重要提示
sp值代表可伸缩像素。这意味着当用户在其 Android 设备上更改字体大小设置时,字体将动态重新调整大小。
现在,搜索gravity属性,并通过单击以下截图中指示的小箭头来展开选项:
图 4.5 - 展开 gravity 属性
通过将该值设置为true,将center_horizontal添加到 gravity 中,如下截图所示:
图 4.6 - 通过将值设置为 true 向 gravity 添加 center_horizontal
gravity属性指的是TextView本身的重力,我们的更改会使TextView内的实际文本居中。
重要提示
gravity属性与layout_gravity属性不同。layout_gravity属性设置布局内的重力,即在这种情况下是父LinearLayout。我们将在项目的后续部分中使用layout_gravity。
此时,我们已更改了TextView小部件的文本,增加了其大小,并使其水平居中。UI 设计师现在应该看起来像这样:
图 4.7 - 调整 UI 上的 textView
快速查看Code选项卡上的 XML,将显示以下代码:
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="Menu"
android:textSize="50sp" />
您可以按如下方式查看新属性:gravity,设置为center_horizontal;text,已更改为Menu;和textSize,设置为50sp。
如果运行应用程序,您可能看不到预期的结果。这是因为我们还没有在我们的 Java 代码中调用setContentView方法来加载 UI。您仍将看到空白的 UI。一旦我们在设计上取得了更多进展,我们将解决这个问题。
将多行 TextView 添加到 UI
切换回我们刚刚添加的TextView小部件。
使用您喜欢的搜索技术,将text属性设置为以下内容:选择布局类型以查看示例。每个按钮的 onClick 属性将调用一个方法,该方法执行 setContentView 以加载新布局。
现在,你的布局将如下所示:
图 4.8 - 添加到 UI 的多行 textView
你的 XML 将在LinearLayout中更新另一个子项(在TextView之后),看起来像这样(我稍微重新格式化了它以便在页面上呈现):
<EditText
android:id="@+id/editTextTextMultiLine"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:gravity="start|top"
android:inputType="textMultiLine"
android:text="Select a layout type to view an example.
The onClick attribute of each button will call a
method which executes setContentView to load the
new layout" />
你可以看到 UI 项的细节。查看 XML 文件,我们有一个inputType属性,表示这个文本是可编辑的。还有另一个我们以前没有见过的属性,那就是ems。ems属性控制每行可以输入多少个字符,值为 10 是由 Android Studio 自动选择的。然而,另一个属性layout_width="match_parent"覆盖了这个值,因为它导致元素扩展以适应其父元素 - 也就是屏幕的整个宽度。
当你在下一节运行应用程序时,你会看到文本确实是可编辑的,尽管对于这个演示应用程序来说,它没有实际用途。
将 UI 与 Java 代码连接起来(第一部分)
为了实现一个交互式的应用程序,我们将做以下三件事:
-
我们将从
onCreate方法中调用setContentView方法来显示我们运行应用程序时 UI 的进展。 -
我们将编写另外两种自己的方法,每种方法都将在不同的布局上调用
setContentView方法(我们还没有设计)。 -
然后,在本章稍后设计另外两个 UI 布局时,我们将能够在点击按钮时加载它们。
因为我们将构建一个ConstraintLayout和一个TableLayout,我们将分别调用我们的新方法loadConstraintLayout和loadTableLayout。
现在让我们这样做,然后我们可以看到如何添加一些调用这些方法的按钮。
切换到MainActivity.java文件,然后在onCreate方法内添加以下突出显示的代码:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_menu);
}
该代码使用setContentView方法来加载我们目前正在工作的 UI。现在你可以运行应用程序来查看以下结果:
图 4.9 - 探索布局菜单
在MainActivity类的onCreate方法之后添加这两个新方法,如下所示:
public void loadConstraintLayout(View v){
setContentView(R.layout.activity_main);
}
public void loadTableLayout(View v){
setContentView(R.layout.my_table_layout);
}
第一种方法有一个错误,第二种方法有两个错误。我们可以通过添加一个import语句来修复第一个错误,以便 Android Studio 知道View类。左键单击View单词以选择错误。按住Alt键然后点击Enter键。你会看到以下消息弹出:
图 4.10 - 选择导入类以消除错误
选择导入类。错误消失了。如果你滚动到代码的顶部,你会看到通过我们刚刚执行的快捷方式添加了一行新的代码。下面是新代码:
import android.view.View;
Android Studio 知道View类,不再有错误。
然而,第二种方法仍然有一个错误。问题在于代码调用setContentView方法来加载一个新的 UI(R.layout.my_table_layout)。由于这个 UI 布局还不存在,它会产生一个错误。你可以注释掉这个调用以消除错误,直到我们在本章后面创建文件并设计 UI 布局为止。添加注释斜杠(//),如下所示:
public void loadConstraintLayout(View v){
setContentView(R.layout.activity_main);
}
public void loadTableLayout(View v){
// setContentView(R.layout.my_table_layout);
}
loadConstraintLayout方法没有错误的原因是该方法加载了由 Android Studio 在生成项目时创建的activity_main.xml布局。
现在,我们想要添加一些按钮,以便单击调用我们的新方法并加载我们将要构建的新布局。但是,添加一些带有文本的按钮太容易了 - 我们以前已经做过了。我们想要做的是将一些文本与按钮对齐,使其位于文本的右侧。问题是,我们的LinearLayout的orientation属性设置为vertical,正如我们所见,我们添加到布局中的所有新部分都将垂直排列。
在布局中添加布局
解决方案是在布局中嵌套布局,以便以不同方向排列一些元素。以下是如何做到的。
从调色板的布局类别中,将一个LinearLayout (Horizontal)拖放到我们的设计中,将其放置在多行文本的正下方。请注意以下截图中,有一个蓝色边框占据了多行文本下方的所有空间:
图 4.11 - 从布局类别将 LinearLayout (Horizontal)拖放到我们的设计中,并将其放置在多行文本的正下方
这表明我们的新**LinearLayout (Horizontal)**正在填充空间。请记住这个蓝色边框区域,因为这将是我们在 UI 上放置下一个项目的地方。
现在,回到新添加的LinearLayout上的TextView小部件。请注意以下截图中,TextView小部件紧密地坐落在新LinearLayout的左上角:
图 4.12 - 从调色板的文本类别将 TextView 小部件拖放到新的 LinearLayout 中
起初,这似乎与之前的垂直LinearLayout发生的情况没有什么不同,它从一开始就是我们 UI 的一部分。但是当我们添加 UI 的下一个部分时,请看看会发生什么。
重要提示
用于指代在布局中添加布局的术语是TextView、Button、LinearLayout)或更广泛的(UI 元素、项目或小部件)。
从先前的TextView小部件的右侧将Button小部件拖放。请注意,按钮位于文本的右侧,如下所示:
图 4.13 - 从按钮类别将按钮小部件拖放到先前 TextView 小部件的右侧
接下来,通过点击其空白部分选择LinearLayout(水平的那个)。找到layout_height属性,并将其设置为wrap_content。请注意,LinearLayout现在只占用所需的空间,并且在下方有空间可以添加更多小部件。如下截图所示:
图 4.14 - 通过点击空白部分选择 LinearLayout (水平的那个)
在添加 UI 的下一部分之前,让我们配置TextView小部件和Button小部件的text属性。将Button小部件的text属性更改为LOAD。将我们新的TextView小部件的文本属性更改为Load ConstraintLayout。
此截图显示了当前布局的外观:
图 4.15 - 配置 TextView 小部件和 Button 小部件的文本属性
提示
那起作用了吗?是的?太棒了。您现在已经熟悉了编辑 Android 视图属性。没有?左键单击要编辑的项目(在本例中为TextView小部件),使用搜索图标进行搜索,或滚动查找要在text属性中编辑的属性),选择属性,然后按Enter进行编辑。现在我可以更简洁地说明如何构建未来的 UI 项目,这将使您成为 Android 忍者的旅程更快。
现在,我们可以重复自己,在刚刚完成的下方再添加一个LinearLayout(水平),分别添加另一个TextView小部件和Button小部件。要这样做,请按照以下顺序进行:
-
在上一个下面添加另一个LinearLayout(水平)。
-
添加一个
LinearLayout。 -
将
TextView的text属性更改为“加载 TableLayout”。 -
在
TextView小部件的右侧添加一个Button小部件。 -
将
Button小部件的text属性更改为LOAD。 -
通过将
layout_height属性更改为wrap_content来调整LinearLayout的大小。 -
只是为了好玩,也为了更多地探索调色板,找到
RatingBar小部件并将其放在设计的下方,就在最后一个LinearLayout下方。
现在,您的 UI 应该是这样的:
图 4.16 - 在另一个 LinearLayout(水平)中添加了另一个 TextView 小部件和 Button 小部件
让我们为布局添加一些视觉上的润色。
使布局看起来漂亮
在本节中,我们将探讨一些控制 UI 细节的更多属性。您可能已经注意到 UI 在某些地方看起来有点挤,而在其他地方看起来不对称。随着我们在书中的进展,我们将不断增加我们的技能来改善我们的布局,但这些简短的步骤将介绍并处理一些基础知识。
在开始下一步之前,请考虑以下提示。
提示
当您配置小部件的属性时,您可以一次选择多个小部件 - 例如,在接下来的说明中的步骤 3中,您可以左键单击以选择第一个TextView小部件,然后Shift和左键单击以选择第二个TextView小部件。然后可以同时更改两者的属性。这个提示也适用于步骤 4和Button小部件。即使小部件类型不同,只要您只编辑所有选定小部件都具有的属性,它也可以工作。因此,在接下来的步骤 5中,您可以同时选择并编辑TextView和两个Button小部件上的“填充”属性。
按照以下说明进行:
-
选择“多行文本”小部件,找到并展开“填充”属性。将“填充”选项设置为
15sp。这在“文本”周围留出了一个整洁的空间。 -
为了在多行文本小部件下面留出一个漂亮的空间,找到并展开
Layout_Margin属性,将bottom设置为50sp。 -
在两个对齐的
TextView小部件上,将textSize属性设置为20sp;layout_gravity设置为center_vertical;layout_width属性设置为match_parent;并将layout_weight设置为.7。 -
在两个按钮上,将权重设置为
.3。注意两个按钮现在都占据了宽度的.3,文本占据了.7的LinearLayout,使整体外观更加愉悦。 -
在两个
TextView小部件和两个Button小部件上,选择“填充”然后选择“填充”,并将值设置为10dp。 -
在
RatingBar小部件上,找到Layout_Margin属性,然后将left和right设置为15sp。 -
仍然使用
RatingBar小部件和Layout_Margin属性,将顶部更改为75sp。
现在,您可以运行应用程序,看到我们的第一个完整布局的全部荣耀,如下所示:
图 4.17 - 改进的布局
请注意,您可以使用RatingBar小部件,尽管在关闭应用程序时评分不会保留。
不幸的是,我们应用程序中的按钮还没有做任何事情。让我们现在修复它。
用 Java 代码连接 UI(第二部分)
为了让用户与我们的按钮交互,按照下面的两个步骤使布局中的按钮调用我们的方法:
-
选择
Load ConstraintLayout文本旁边的按钮。找到onClick属性并将其设置为loadConstraintLayout。 -
选择
Load TableLayout文本旁边的按钮。找到onClick属性并将其设置为loadTableLayout。
现在,按钮将调用方法,但loadTableLayout方法内的代码被注释掉以避免错误。随时运行应用程序并检查您是否可以通过单击loadConstraintLayout按钮切换到ConstraintLayout。但是ConstraintLayout目前只有一个**Hello World!**消息。
现在,我们可以继续构建这个ConstraintLayout。
使用 ConstraintLayout 构建精确的 UI
打开我们创建项目时自动生成的ConstraintLayout。它可能已经在编辑器顶部的选项卡中打开了。如果没有,它将在res/layout文件夹中。文件名是activity_main.xml。
检查Hello World中的TextView中的 XML。切换回Design选项卡,左键单击TextView以选择它,然后按Delete键将其删除。
现在,我们可以构建一个简单而复杂的 UI。当您想要非常精确地定位 UI 的部分和/或相对于其他部分而不仅仅是线性方式时,ConstraintLayout是最有用的。
添加日历视图
要开始,请查看CalendarView。将CalendarView拖放到顶部并水平居中。当您拖动CalendarView时,请注意它会跳到某些位置。
另外,注意显示视图对齐时的微妙视觉提示。我在下面的截图中突出显示了水平中心的视觉提示:
图 4.18 - 水平中心的视觉提示
当它水平居中时,就像前面的截图中一样,松开。现在,我们将调整它的大小。
在 ConstraintLayout 中调整视图大小
左键单击并按住CalendarView释放时显示的角落中的一个,向内拖动以减小CalendarView的大小,如下面的截图所示:
图 4.19 - 在 ConstaintLayout 中调整视图大小
将大小减少约一半,将CalendarView留在顶部并水平居中。在调整大小后,您可能需要重新定位小部件。结果应该是这样的:
图 4.20 - 重新定位小部件
您不需要将CalendarView放在完全相同的位置,因为练习的目的是熟悉通知您放置位置的视觉提示,而不是创建我的布局的复制品。
使用 Component Tree 窗口
现在,看看Component Tree窗口,即可视化设计师左侧和调色板下方的窗口。组件树是一种可视化 XML 布局的方式,但没有所有细节。
如果您没有看到这个,请在Palette选项卡底部找到一个标签,上面写着垂直的 Component Tree。单击它以打开Component Tree选项卡。
在下一个截图中,我们可以看到CalendarView向右缩进到ConstraintLayout的右侧,因此是一个子级。在我们构建的下一个 UI 中,我们将看到有时需要利用Component Tree来构建 UI。
现在,我只是想让您看到我们的CalendarView旁边有一个警告标志。我在这里突出显示了它:
图 4.21 - 我们的 CalendarView 旁边的警告标志
错误提示此视图没有约束。它只有设计时位置,因此在运行时会跳转到(0,0),除非你添加约束。还记得当我们在*第二章**中首次向屏幕添加按钮时,它们只是移动到左上角吗?
提示
现在运行应用程序,如果你想提醒自己这个问题,请点击加载 ConstraintLayout按钮。
现在,我们可以通过点击我们在*第二章中使用的推断约束**按钮来修复这个问题。这里再次提醒一下:
图 4.22 - 点击推断约束按钮修复错误
但是学会手动添加约束是值得的,因为它为我们提供了更多的选项和灵活性。而且,当你的布局变得更加复杂时,总会有一两个项目的行为不如你所愿,手动修复几乎总是必要的。
手动添加约束
确保选择了 CalendarView,并注意下图中顶部、底部、左侧和右侧的四个小圆圈:
图 4.23 - 四个约束手柄
这些是 CalendarView 与屏幕的四个边缘,当应用程序运行时,我们可以将其锁定在位置上。
依次点击并拖动顶部手柄到设计的顶部,右侧手柄到设计的右侧,底部手柄到底部,左侧手柄到左侧。注意当我们应用这些约束时,CalendarView 是如何跳动的?这是因为设计师在我们放置约束时立即应用约束,所以我们可以看到它在运行时的实际效果。
注意,CalendarView 现在在中间约束了。左键单击并拖动 CalendarView 回到屏幕的上部,位置大致如下截图所示。使用视觉线索(也显示在下一个截图中)确保 CalendarView 水平居中:
图 4.24 - 使 CalendarView 水平居中
在这个阶段,你可以运行应用程序,CalendarView 将被定位为前面截图中所示。
让我们向 UI 添加更多项目并看看如何约束它们。
添加和约束更多的 UI 元素
从 CalendarView 中拖动一个 ImageView。当你放置 ImageView 时,会弹出一个窗口提示你选择一张图片。你可以选择任何你喜欢的图片,但是为了看到另一个 Android Studio 功能的效果,请选择列表顶部的图片Avatar,在示例数据部分。点击确定将图片添加到布局中。我们将在接下来的使文本可点击部分看到从示例数据部分添加图片对我们项目的影响。
将 ImageView 的左侧和底部分别约束到 UI 的左侧和底部。现在你应该处于这个位置:
图 4.25 - 将 ImageView 的左侧和底部分别约束到 UI 的左侧和底部
ImageView 在左下角被约束。现在,抓住 ImageView 上的顶部约束手柄,并将其拖动到 CalendarView 的底部约束手柄。现在的情况是:
图 4.26 – 编辑后的 UI
ImageView 只在水平方向上有约束,因此被固定/约束在左侧。它在CalendarView和 UI 底部之间垂直并且等距约束。
接下来,在ImageView的右侧添加一个TextView。将TextView的右侧约束到 UI 的右侧,并将TextView的左侧约束到ImageView的右侧。然后,将TextView的顶部约束到ImageView的顶部,并将TextView的底部约束到 UI 的底部。现在,您将得到类似于以下内容:
图 4.27 – 将 TextView 添加到 UI
重要提示
strings.xml文件中的所有警告,以及有关缺少contentDescription属性的警告。contentDescription属性应用于添加文本描述,以便视力受损的用户可以在应用程序中获得图像的口头描述。为了快速进展ConstraintLayout,我们将忽略这两个警告。我们将在第十八章中更正确地添加字符串资源,本地化,您可以在Android 开发者网站上阅读有关 Android Studio 的辅助功能的信息,网址为developer.android.com/studio/intro/accessibility。
您可以移动三个 UI 元素并将它们整齐地排列,就像您想要的那样。请注意,当您移动ImageView时,TextView也会随之移动,因为TextView受到ImageView的约束。但也请注意,您可以独立移动TextView,无论您放在哪里,这都代表了它相对于ImageView的新约束位置。无论一个项目受到什么约束,它的位置始终是相对于该项目的。正如我们所见,水平和垂直约束是彼此独立的。我将我的位置放在这里:
图 4.28 – 定位 TextView
提示
ConstraintLayout可以被认为是默认的布局类型,虽然它比其他布局更复杂,但它是最强大的,也是在我们用户设备上运行最好的。值得花时间查看一些关于ConstraintLayout的更多教程。特别是在YouTube上查看,因为视频是学习调整ConstraintLayout的好方法。我们将在整本书中回到ConstraintLayout,而且您不需要知道比我们已经涵盖的更多内容才能继续前进。
使文本可点击
我们的ConstraintLayout快要完成了。我们只想要连接回主菜单屏幕的链接。这是一个很好的机会来演示TextView(以及大多数其他 UI 项)也是可点击的。事实上,可点击的文本在现代 Android 应用程序中可能比传统的按钮更常见。
将TextView小部件的text属性更改为“返回菜单”。现在,找到onClick属性,并输入loadMenuLayout。
现在,在MainActivity.java文件中,在loadTableLayout方法之后添加以下方法,如下所示:
public void loadTableLayout(View v){
//setContentView(R.layout.my_table_layout);
}
public void loadMenuLayout(View v){
setContentView(R.layout.main_menu);
}
现在,每当用户点击时,loadMenuLayout方法将被调用,并且setContentView方法将在main_menu.xml中加载布局。
您可以运行应用程序,并在主菜单(LinearLayout)和CalendarView小部件(ConstraintLayout)之间来回点击,但您是否注意到以下截图中的图像似乎丢失了?
图 4.29 – UI 中缺少的图像
TextView小部件被整齐地定位,就好像ImageView小部件在那里一样,但是从前面的屏幕截图中可以看到,Android Studio 中可见的头像图标已经消失了。这是因为我们选择了示例数据类别中的图像。Android Studio 允许我们使用示例数据,这样我们就可以在图像可用之前继续布局我们的应用程序。这很有用,因为在应用程序的开发生命周期中通常需要制作/获取图像。
为了解决这个缺失图像的问题,我们可以在Attributes窗口中找到srcCompat属性,左键单击它,并选择不是来自sym_def_app_icon的任何图像,这是下一个酷炫的 Android 图标:
图 4.30 - 从 srcCompat 属性添加图标
让我们为本章构建最终布局。
使用 TableLayout 布局数据
现在,我们将构建一个类似电子表格的布局。它将具有整齐对齐的带有标题和数据的单元格。在真实的应用程序中,您很可能会使用来自用户的真实实时数据。由于我们只是练习不同的布局,我们不会走到这一步。
按照以下步骤:
-
在项目窗口中,展开
res文件夹。现在,右键单击layout文件夹,然后选择New。注意到有一个Layout resource file选项。 -
选择Layout resource file,然后您将看到New Resource File对话框窗口。
-
在
my_table_layout中。这与我们在loadTableLayout方法中对setContentView的调用中使用的名称相同。 -
注意
ConstraintLayout中的TableLayout。 -
单击 XML 文件中的
TableLayout,命名为my_table_layout,并将其放在layout文件夹中,准备构建我们的基于表格的新 UI。如果 UI 设计师尚未打开,Android Studio 还将打开 UI 设计师,左侧是调色板,右侧是Attributes窗口。 -
现在,您可以取消注释
MainActivity.java文件中的loadTableLayout方法,如下所示:
void loadTableLayout(View v){
setContentView(R.layout.my_table_layout);
}
现在,当您运行应用程序时,可以切换到具有新的TableLayout小部件的屏幕,尽管目前它是空白的,并且没有办法切换回主菜单屏幕;因此,您将不得不退出应用程序。
向 TableLayout 添加一个 TableRow 元素
从Layouts类别中拖放一个TableRow元素到 UI 设计中。请注意,这个新的TableRow元素的外观几乎是不可察觉的,以至于不值得在书中放置它的屏幕截图。UI 顶部只有一条蓝线。这是因为TableRow元素已经将其内容折叠在一起,而这些内容目前是空的。
我们可以将所选的 UI 元素拖放到这条蓝线上,但这也有点麻烦,甚至有点违反直觉。此外,一旦我们在一起有多个TableRow元素,情况就会变得更加困难。解决方案在于ConstraintLayout。
使用组件树进行可视化设计师无法完成的布局
将TableRow视为TableLayout的子元素。我们可以直接将新的 UI 小部件拖放到TableRow中,在Component Tree中的TextView小部件拖放到TableRow中,这样就会得到以下布局。我已经使用 Photoshop 修改了下一个屏幕截图,以便同时显示Component Tree和常规 UI 设计师:
图 4.31 - 将三个 TextView 小部件拖放到组件树中的 TableRow 元素上
现在,添加另外两个TableRow小部件(来自Layouts类别)。您可以通过Component Tree窗口或主 UI 设计师添加它们。
提示
您需要将小部件放在窗口的最左侧,否则新的TableRow将成为上一个TableRow的子级。这将使整个表格变得有些混乱。如果您意外地将TableRow添加为上一个TableRow的子级,您可以选择它,然后点击删除键,使用Ctrl + z键组合进行撤消,或者将位置错误的TableRow拖到左侧(在Table中而不是TableRow)。
现在,向每个新的TableRow元素添加三个TextView小部件。最简单的方法是通过组件树窗口添加它们。检查您的布局,确保它是这样的:
图 4.32 – 向每个新的 TableRow 元素添加三个 TextView 小部件
让我们通过更改一些属性使表格看起来更像您可能在应用程序中获得的真实数据表。
在TableLayout上,将layout_width和layout_height属性设置为wrap_content。这样可以去掉多余的单元格
通过编辑textColor属性,将所有外部(顶部和左侧)的TextView小部件更改为黑色。您可以通过选择第一个TextView,搜索其color属性,然后开始在color属性值字段中输入black来实现这一点。然后,您将能够从下拉列表中选择@android:color/black。对每个外部TextView小部件都这样做。
提示
请记住,您可以通过按住Shift键并依次左键单击每个所需的小部件来同时选择多个小部件。
找到所有TextView小部件的padding类别,并将padding属性更改为10sp。
下一个截图显示了此时在 Android Studio 中表格的样子:
图 4.33 – Android Studio 中的表格
让我们为表格添加一些最后的修饰。
组织表格列
此时似乎我们已经完成了,但是我们需要更好地组织数据。我们的表格,就像许多表格一样,将在左上角有一个空白单元格来分隔列和行标题。为了实现这一点,我们需要对所有单元格进行编号。为此,我们需要编辑layout_column属性。
提示
单元格编号从左边开始从 0 开始。
首先删除左上角的TextView。注意右侧的TextView已经移动到左上角位置。
接下来,在新的左上角TextView中,编辑layout_column属性为1(这将其分配给第二个单元格,因为第一个单元格是0,我们希望将第一个单元格留空),并且对于下一个单元格,编辑layout_column属性为2。
结果应该是这样的:
图 4.34 – 表列组织
对于下面两行单元格,从左到右将它们的layout_column属性从0更改为2。
如果您在编辑后想要对此行的精确代码进行澄清,请参阅以下代码片段,并记得在第四章文件夹中的下载包中查看整个文件的上下文。
重要提示
text attributes throughout.
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_column="1"
android:padding="10sp"
android:text="India"
android:textColor="@android:color/black" />
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_column="2"
android:padding="10sp"
android:text="England"
android:textColor="@android:color/black" />
</TableRow>
尝试完成这个练习,如果可能的话,使用属性窗口。
链接回主菜单
最后,对于这个布局,我们将添加一个按钮,链接回菜单,如下所示:
-
通过组件树添加另一个
TableRow。 -
将一个按钮拖到新的
TableRow上。 -
将其
layout_column属性编辑为1,使其位于行的中间。 -
将其
text属性编辑为Menu,并将其onClick属性编辑为匹配我们已经存在的loadMenuLayout方法。
现在,您可以运行应用程序并在不同的布局之间来回切换。
如果你愿意,你可以通过编辑 TextView 的所有text属性向表格添加一些有意义的标题和数据,就像我在下面的截图中所做的那样,它展示了在模拟器中运行的 TableLayout:
图 4.35 - 通过编辑 TextView 的所有文本属性向表格添加一些重要的标题和数据
注意
作者承认,前述数据可能被认为过于乐观。
最后,想想一个展示数据表的应用程序。很可能数据将动态地添加到表中,而不是由开发人员在设计时像我们刚刚做的那样,而更可能是由用户或来自网络上的数据库添加。在第十六章,适配器和回收器中,我们将看到如何使用适配器动态地向不同类型的布局添加数据;在第二十七章,Android 数据库中,我们还将看到如何在我们的应用程序中创建和使用数据库。
总结
我们在短短几十页中涵盖了许多主题。我们不仅构建了三种不同类型的布局,包括带有嵌套布局的LinearLayout,手动配置约束的ConstraintLayout,以及TableLayout(尽管使用的是虚假数据),而且还通过可点击的按钮和文本将所有布局连接在一起,触发我们的 Java 代码在所有这些不同的布局之间切换。
在下一章中,我们将继续讨论布局的主题。我们将回顾我们已经见过的许多属性,并且通过将多个CardView布局整合到一个平滑滚动的ScrollView布局中,构建迄今为止最美观的布局。