开发体验

第7章 安卓,我的车在哪儿?

你已经把车停得尽可能靠近体育馆,但是演唱会结束时,你还是忘了停车的位置,你的同伴也是一脸茫然。幸运的是,你的安卓手机还在,它从来不忘事。你新安装了一款热门应用“安卓,我的车在哪儿?”,有了这个应用,在停车时点一下按钮,手机会让它的位置传感器“记住”当前位置的GPS坐标以及地址。当稍后重新打开应用时,它会指给你从当前位置到停车位置的方向,问题解决了!

学习要点

应用“安卓,我的车在哪儿?”涵盖如下概念。

  • 位置传感器组件:确定安卓设备的位置。
  • 本地数据库组件:直接在设备数据库中永久保存数据。
  • Web浏览框组件:在应用中打开谷歌地图,并显示从一个位置到另一个位置的方向。

准备开始

登录App Inventor网站,创建一个新项目“安卓找车”(项目名称不能有空格),将屏幕标题设置为“安卓,我的车在哪儿?”,连接测试设备或模拟器,以便进行实时测试。

设计组件

此应用的用户界面包含两类可视组件——标签及按钮。

  • 多个标签组件:显示当前位置和曾经保存过的位置信息。有些标签用于显示静态文本,如GPS标签显示“GPS:”;另一些标签,如当前经纬度标签用于显示来自位置传感器的数据。给经纬度标签设定一个默认值(0,0),当GPS取得位置信息时,这个值将随之改变。
  • 两个按钮组件:记录位置和指示该位置的方向。

应用中还包括三个非可视组件。

  • 位置传感器组件:用于获取当前位置信息。
  • 本地数据库组件:用于永久保存位置信息。
  • Web浏览框组件:用于在谷歌地图上指示方向(从当前位置指向已记录的位置)。

如图7-1所示,在设计视图中创建组件。

图7-1 设计视图中的“安卓,我的车在哪儿?”应用

按照表7-1中的内容创建组件。

表7-1 应用中的全部组件

组件类型 所属类别 名称 作用
标签 用户界面 当前信息标题标签 显示标题:当前位置
水平布局 组件布局 水平布局1 放置地址信息
标签 用户界面 当前地址标签 显示文字“地址:”
标签 用户界面 当前地址数据标签 显示动态数据:当前位置的地址信息
水平布局 组件布局 水平布局2 放置GPS信息
标签 用户界面 当前GPS标签 显示文字“GPS:”
标签 用户界面 当前纬度标签 显示动态数据:当前位置的纬度
标签 用户界面 逗号标签1 显示“,”
标签 用户界面 当前经度标签 显示动态数据:当前位置的经度
按钮 用户界面 记录按钮 点击记录当前位置信息
标签 用户界面 记录信息标题标签 显示“已记录的地点”
水平布局 组件布局 水平布局3 放置记录的地址信息
标签 用户界面 记录地址标签 显示“地址:”
标签 用户界面 记录地址数据标签 显示动态数据:已记录的地址信息
水平布局 组件布局 水平布局4 放置已记录的GPS信息
标签 用户界面 记录GPS标签 显示文字“GPS:”
标签 用户界面 记录纬度标签 显示动态数据:已记录的纬度
标签 用户界面 逗号标签2 显示“,”
标签 用户界面 记录经度标签 显示动态数据:已记录的经度
按钮 用户界面 显示方向按钮 点击来显示地图
位置传感器 传感器 位置传感器1 感知GPS信息
本地数据库 数据存储 本地数据库1 永久保存记录的位置信息
Web浏览框 用户界面 Web浏览框1 显示地图并指示方向

按以下方式设置组件属性:

  • 勾选两个标题标签的粗体属性;
  • 设置显示静态文本标签的显示文本属性为固定文本,参照表7-1;
  • 设置显示动态GPS数据(经纬度)标签的显示文本属性为“0.0”;
  • 设置显示动态地址标签的显示文本属性为“未知”;
  • 取消勾选记录按钮及指示方向按钮的启用属性(设置为不可用);
  • 取消勾选Screen1的允许滚动属性,以便Web浏览框能够适应屏幕的大小。

为组件添加行为

需要为应用设定如下行为。

  • 当位置传感器读取到位置信息时,将数据填写到相应的标签中,表示传感器已经读取到当前位置信息,用户这时可以选择保存此位置信息。
  • 当用户点击记录按钮时,当前位置信息被复制到“已记录的地点”名下的标签中。这些信息要保存到设备数据库中,以便用户关闭并再次打开应用时,数据不会消失。
  • 当用户点击指示方向按钮时,在Web浏览框中打开谷歌地图,以便显示已记录位置的方向。
  • 当应用重新启动时,从数据库中加载已记录的位置信息。

显示当前位置

两种情况会触发位置传感器的位置信息改变事件:(1)传感器首次读取到位置信息时;(2)设备的位置变化导致传感器的读数更新时。首次读数有时仅需几秒钟,但如果GPS卫星信号受到屏蔽,就会一直没有读数(也可能与设备的设置有关)。有关GPS和位置传感器的更多信息,请参见第23章。

在读取到位置信息时,程序要将数据写到相应的标签中。表7-2列出了这项功能所需要的代码块。

表7-2 读取并显示位置信息所需要的块

代码块 所在抽屉 作用
当位置传感器1位置信息改变时 位置传感器1 当手机收到新的GPS读数时,触发该事件
设当前地址数据标签的显示文本为 当前位置数据标签 用标签显示当前地址的最新数据
位置传感器1的当前地址 位置传感器1 保存街区地址的属性
设当前纬度标签的显示文本为 当前纬度标签 用标签显示当前的纬度值
纬度 从位置传感器1的位置信息改变事件中拖出 填充到“设当前纬度标签的显示文本为”块中
设当前经度标签的显示文本为 当前经度标签 用标签显示当前的经度值
经度 从位置传感器1的位置信息改变事件中拖出 填充到“设当前经度标签的显示文本为”块中
设记录按钮的启用为 记录按钮 获得当前位置的数据后,改变记录按钮的不可用状态
逻辑 填充到“设记录按钮的启用为”块中

块的作用

如图7-2所示,纬度和经度是位置信息改变事件的参数,因此可以直接从事件块中拖出(将鼠标悬停在参数名称上);但当前地址不是参数,而是位置传感器的属性,因此要从位置传感器的抽屉里选取。位置传感器除了可以获取GPS位置信息之外,还可以通过调用谷歌地图,获得与位置信息相对应的街道地址信息。

图7-2 利用位置传感器获得当前位置信息

事件处理程序还启用了记录按钮,该按钮的启用属性初始为禁用(在设计视图中未勾选),因为在传感器获得数据之前,用户没有数据可以记录,而现在我们可以设置应用的记录行为了 。

测试:这个应用无法在室内进行测试,你必须带着手机走到户外,这需要将应用打包安装到手机上。选择菜单中的“编译→显示二维码”,扫描二维码就可以将应用下载并安装到手机上。当应用开始运行时,你的手机会收到并显示某些GPS数据,同时,记录按钮变为可用。如果你一直没有收到数据,检查一下设备设置中的位置信息访问权限,打开“访问我的位置信息”,然后再到户外试试看。更多信息请参看第23章。

记录当前位置

当用户点击记录按钮时,当前位置信息被写入“已记录的地点”下方的标签中。表7-3显示了实现这一功能所需要的代码块。

表7-3 记录并显示当前位置所需要的块

代码块 所在抽屉 作用
当记录按钮被点击时 记录按钮 当用户点击“记录当前位置”时,触发该事件
设记录地址数据标签的显示文本为 记录地址数据标签 用标签显示传感器中的地址数据
位置传感器1的当前地址 位置传感器1 该属性保存了当前地址信息
设记录纬度标签的显示文本为 记录纬度标签 用标签显示位置传感器获得的纬度信息
位置传感器1的纬度 位置传感器1 将该块填充到“设记录纬度标签的显示文本为”块中
设记录经度标签的显示文本为 记录经度标签 用标签显示位置传感器获得的经度信息
位置传感器1的经度 位置传感器1 将其填充到“设记录经度标签的显示文本为”块中
设指示方向按钮的启用为 指示方向按钮 改变指示方向按钮的未启用状态,以便用户可以打开已记录地点的地图
逻辑 将该块填充到“设指示方向按钮的启用为”块中

块的作用

当用户点击“记录当前位置”按钮时,当前位置信息将写入“已记录”区域的标签中,如图7-3所示。

图7-3 用已记录区域的标签显示当前位置信息

注意,指示方向按钮已经可用,这会有一点儿小麻烦,因为如果用户立即点击指示方向按钮,已记录的位置信息就是当前的位置信息,因而地图中不会提供与方向有关的信息。但是,人们似乎不会这么做;当用户移动位置时(例如步行到演唱会),当前位置将偏离已记录位置。

测试:将应用的新版本下载到手机上,并再次测试。当单击记录按钮时,当前位置信息是否被写入“已记录”区域的标签中?

指示记录位置的方向

我们希望当用户点击指示方向按钮时,应用将打开谷歌地图,地图中指示方向:从用户当前位置到已记录位置(即停车位置)。

Web浏览框组件可以显示任何网页,包括谷歌地图。调用Web浏览框1的访问网页功能可以打开地图,但我们要打开的是一张能够指示从当前位置到已记录位置方向的地图。

下面的网址可以显示一张带有方向的地图:http://maps.google.com/maps?saddr=37.82557,-122.47898&daddr=37.81079,-122.47710

将上述网址输入到浏览器的地址栏中,说说看,它指引你跨越了哪个著名的地标性建筑?

这需要在编程视图中动态地生成网址,并为网址设置两个参数:起点地址(saddr)和终点地址(daddr)。在前几章中,你已经学会用“拼字串”块将文本连接起来,这里也是如此。将当前位置和已记录位置的GPS数据插入到网址中,并将网址填充到Web浏览框1的访问网页命令的插槽中。表7-4 列出了实现这一功能所需的所有代码块。

表7-4 指示方向的块:从当前位置指向已记录位置

代码块 所在抽屉 作用
当指示方向按钮被点击时 指示方向按钮 当用户点击指示方向按钮时触发
让Web浏览框1访问网页 Web浏览框1 设置网址来打开你需要的地图
拼字串 文本 将多个文本片断连接起来生成动态网址
文本“http://maps.google.com/maps?saddr= 文本 网址中不变的部分,紧接着是起点经纬度
当前纬度标签的显示文本 当前纬度标签 当前位置的纬度值
文本“,” 文本 在纬度值与经度值之间有一个逗号
当前经度标签的显示文本 当前经度标签 当前位置的经度值
文本“&daddr=” 文本 用于连接网址中的第二个参数——终点经纬度
记录纬度标签的显示文本 记录纬度标签 已记录位置的纬度值
文本“,” 文本 在纬度值与经度值之间有一个逗号
记录经度标签的显示文本 记录经度标签 已记录位置的经度值

块的作用

用户点击指示方向按钮时,事件处理程序生成一个地图网址,然后调用Web浏览框1的访问网页命令来打开地图,如图7-4所示。拼字串块用于生成地图网址。

最终的网址中包含了地图域名(http://maps.google.com/maps )以及两个网址参数:saddr与daddr,指示方向所需的起点及终点信息。在本应用中,saddr被设定为当前位置的纬度和经度,而daddr被设定为已记录的停车位置的纬度和经度。

图7-4 生成网址,以便用Web浏览框来打开地图

测试:用手机下载新的版本并再次测试。一旦取得读数,单击记录按钮,然后走到远处。当单击指示方向按钮时,地图是否提示你如何回溯自己的足迹?查看完地图后,点击几次回退按钮。你返回到应用了吗?

永久保存已记录的位置信息

现在已经具备了一个全功能的应用:记住起点位置,绘制一张能够指示方向的地图,从用户的当前位置指向起点位置。虽然用户记录了起点的位置,但假如用户关闭应用,稍后再重新打开应用时,记录的信息将不复存在。实际上你设想的使用情境是:用户记录下车的位置,随后关闭应用,去忙别的事情,并在需要时重新启动应用,来获取已记录位置的方向。

如果你能想起“开车不发短信”应用(第4章),说明你的思路是正确的。我们需要使用本地数据库组件来永久保存这些数据,组件的使用方法与此前的用法类似。

  1. 当用户点击记录按钮时,将位置信息存储到数据库中。
  2. 当应用启动时,从数据库中加载位置信息并保存到一个变量或属性中。

首先,修改记录按钮的点击事件处理程序,来存储这些需要记录的信息。存储纬度、经度和地址三组信息,需要三次调用本地数据库的保存数据功能。表7-5列出了所要补充的代码块。

表7-5 永久保存当前位置信息所需要的块

代码块 所在抽屉 作用
让本地数据库1保存数据(3个) 本地数据库1 将数据保存到设备数据库中
文本“地址” 文本 填充到“让本地数据库1保存数据”的“参数:标记”插槽中
位置传感器1的当前地址 位置传感器1 永久保存地址信息,将其填充到“让本地数据库1保存数据”块的“参数:数值”插槽中
文本“纬度” 文本 填充到“让本地数据库1保存数据”的“参数:标记”插槽中
位置传感器1的纬度 位置传感器1 永久保存纬度信息,将其填充到“让本地数据库1保存数据”块的“参数:数值”插槽中
文本“经度” 文本 填充到“让本地数据库1保存数据”的“参数:标记”插槽中
位置传感器1的经度 位置传感器1 永久保存经度信息,将其填充到“让本地数据库1保存数据”块的“参数:数值”插槽中

块的作用

如图7-5所示,本地数据库1的保存数据功能将位置传感器属性中的位置信息保存到数据库中。你该记得在“开车不发短信”中,保存数据功能有两个参数,标记与数值,标记用于区分已经存储的数据,数值是你实际想保存的数据,即本例中的位置传感器数据。

图7-5 将已记录的位置信息保存到数据库中

启动应用时提取已记录的位置信息

将数据保存在数据库中,是为了以后可以调用它。在本应用中,你设想用户的使用情境如下:用户保存位置信息之后退出应用,当应用被重新打开时,从数据库中读出信息,并显示在用户界面上。

在前几章中讨论过,当应用启动时,会触发屏幕的初始化事件,此时从数据库中读取数据是一种编程的惯例,本应用也不例外。

使用本地数据库的请求数据块来读取已经存储的GPS数据,要读取的数据包括地址、纬度及经度,因此要三次执行请求数据命令。像在“开车不发短信”中一样,要事先检查数据库中是否保存了数据(如,应用在第一次启动时,请求数据命令将返回一个空文本)。

挑战一下自己,看看是否可以独立创建这些块,然后再与图7-6进行比较。

图7-6 当应用启动时,从数据库中加载已记录的位置信息

块的作用

为了理解这些代码块,我们来设想两种使用情境:用户首次打开应用,并保存位置信息;稍后用户再次打开应用。首次打开应用时,数据库中没有信息可加载,此后再次启动应用时,如果数据库中保存了数据,则加载这些位置信息。

这里三次调用请求数据功能,分别请求地址、纬度及经度信息。参数“无标记返回”用于处理数据库中不存在数据的情形,即,当请求的标记不存在时返回事先设定的默认值,此时,相关标签的显示文本将被设置为这些默认值(与设计视图中设定的默认值相同)。

“如果...则”块用来判断数据是否存在,并继而决定是否启用指示方向按钮。如果数据库中确实存在数据,则启用该按钮。进行判断的条件是记录地址数据标签的显示文本属性是否等于默认值“未知”,如果不等于“未知”,则说明显示文本已经被替换成已记录的地址。

测试:将新版本应用下载到手机,并再次测试。点击记录按钮,并确保数据已被保存。关闭应用并再次打开。那些已保存数据是否还在?

完整的“安卓,我的车在哪儿?”应用

图7-7 显示了完整的“安卓,我的车在哪儿?”应用中的全部代码块。

图7-7 “安卓,我的车在哪儿?”应用中的全部代码块

改进

可以尝试如下改进。

  • 创建一个“安卓,他们在哪儿?”应用,让一个小组内的成员可以了解彼此的行踪。无论你在徒步旅行还是在公园散步,这个应用都有助于你节省时间,甚至可能挽救生命。应用中的数据在组员之间共享,因此要使用网络数据库组件来替代本地数据库组件。更多信息请参见第22章。
  • 创建一个“面包屑”{![源于神话故事《奇幻森林历险记》,故事的两个小主人公丢下一条面包屑路径,然后顺着这条路径回到了家中。——译者注]}应用,用列表来记录自己的位置改变。当记录的位置数量达到某个上限时,或超过一定时间时,开始记录一个新的“面包屑”,因为即使是很短距离的位置移动也会产生一个新的位置数据。这类应用需要使用列表来存储位置记录,详见第19章。

小结

下面是本章涉及的一些概念。

  • 位置传感器组件:可以报告用户的纬度、经度及当前的街区地址。当传感器首次获得数据或数据发生变化(设备移动)时,将触发传感器的位置信息改变事件。有关位置传感器的更多信息,请参见第23章。
  • Web浏览框组件:可以在应用中显示任何网页,包括谷歌地图。如果要显示两个GPS坐标之间的方向,网址必须遵从下面的格式,不过你可以用实际位置的GPS坐标来替换下面的示例数据:http://maps.google.com/maps/?saddr=0.1,0.1&daddr=0.2,0.2。
  • 拼字串块:用来将文本片段连接成一段完整的文字,也可以让静态文本与动态数据相连接。对于地图网址来说,GPS坐标就是动态数据。
  • 本地数据库组件:用于在设备数据库中永久地保存数据。保存在变量或属性中的数据,会随着应用的关闭而丢失,但存储在数据库中的数据,可以在每次启动应用时被载入。有关本地数据库和数据库的详细信息,请参见第22章。