本节课我们来做一款“开车不发短信”的应用,一个“短信应答机”,当你正在开车(或忙于工作)时,它能自动回复收到的短信,还可以大声读出短信的内容,甚至可以在自动回复的短信中报告你当前所在的位置。这款应用中用到了安卓手机的短信收发、语音合成、数据永久保存以及GPS定位等功能,为你提供了一个充分挖掘安卓手机潜能的范例。
2010年1月,美国国家安全委员会(NSC)发布了一项研究结果,每年有至少28%的交通事故——将近160万次车祸源于司机在开车时使用手机,其中至少20万次交通事故与司机收发短信有关 。因此,许多州已经全面禁止司机开车时使用手机。 Daniel Finnegan,一名旧金山大学的学生,在App Inventor编程课上,提出了一个了不起的想法,用一个应用来解决开车时收发短信泛滥的问题。如图4-1所示,他创建的应用可以对收到的任何短信进行自动回复(且免提),如回复“我正在开车,稍后与您联系”之类的内容。
就在这款应用发布到App Inventor网站上的几周之后,联邦农业保险公司(State Farm Insurance) 创建了一款名为“行进中(On the Move)”的安卓应用,其功能与“开车不发短信”类似。
我们无法确认Daniel的应用或App Inventor网站的教程是否对“行进中”产生了影响,但有趣的是,这让我们思考一种可能性:在一门编程基础课上创建的应用(竟然由一名学习创意写作的学生创建!)或许真的催生了这款装机量巨大的软件,或者,至少是对软件产业的生态有所贡献。当然,这也说明了App Inventor降低了软件开发的门槛,以至于无论是谁,只要有一个好主意,都可以快速、低成本地把灵感变成一个实实在在的、可交互的应用。连线杂志(Wired)的Clive Thompson捕捉到了这股新的气息,并写道:
总之,软件几乎影响了我们周围的一切。让我们来盘点一下那些重大的问题——全球变暖、医疗保健,还有Finnegan的例子中的高速公路安全问题,在这些问题的解决方案中,都少不了那些智能软件的参与。当然,只有少数人打算去学习编程,这意味着,社会中蕴藏的巨大创造力还有待我们去发掘。
App Inventor正是Thompson所说的那个发掘创造力的工具,它向每个人敞开了软件创作之门(注意:是创作而不是开发,就像写作一样,人人都可以表达自己,而技术不再成为创作的门槛!——译者注)。
学习内容
相比前几章来说,本章的应用更为复杂,因此我们每次只完成一项功能,从自动回复开始。以下是将要学习的内容:
- 短信收发器组件:用于处理收到的短信并发送短信;
- 文本输入框组件:用于输入自定义回复信息(配合按钮点击事件保存该信息);
- 本地数据库组件:用于在安卓手机中保存自定义信息,即使是关闭应用,信息也不会丢失;
- 屏幕初始化事件:在应用启动时加载自定义回复信息;
- 语音合成器组件:用于读出短信中的文字;
- 位置传感器组件:报告司机的当前位置。
准备开始
打开浏览器,进入App Inventor网站,创建一个新项目,将其命名为“开车不发短信”(记住,项目名不能包含空格),并将Screen1的标题属性设置为“开车不发短信”。点击连接→AI伴侣,或运行模拟器,为实时测试做好准备。
设计组件
应用的用户界面很简单,包含四个可视组件:第一个标签用于显示这款应用的功能,第二个标签用于显示自动回复短信的内容,一个文本输入框用于编辑或修改自动回复短信的内容,一个按钮用于保存已经编辑好的自定义短信内容;应用中还包含四个非可视组件:短信收发器组件、本地数据库组件、语音合成器组件以及位置传感器组件,它们将出现在“不可视组件”区。你可以在图4-2中看到上述组件在设计视图中的样子。
表4-1 应用中的所有组件
按照以下方式设置组件属性:
- 设置功能说明标签的显示文本属性为“本应用在运行时,将使用以下文字自动回复收到的短信。”
- 设置回复内容标签的显示文本属性为“我正在开车,稍后与您联系。”并勾选粗体属性;
- 设置自定义短信输入框的显示文本属性为“”(让文本框为空,等待用户输入);
- 设置自定义短信输入框的提示属性为“请输入自定义短信内容”,宽度设为“充满”;设置保存按钮的显示文本属性为“保存”。
为组件添加行为
最先实现自动回复功能——对收到的任何短信进行回复;然后实现短信内容的自定义功能——让用户可以编写个性化的回复内容,并将内容永久保存在手机中;最后,让应用大声读出收到的短信,并将手机当前的位置信息添加到自动回复内容中。
来信的自动回复
短信的自动回复功能需要用到App Inventor中的短信收发器组件,可以把它想象成一个藏在手机里的小矮人,它知晓如何收发短信。当手机接收到一条短信时,将触发该组件的“收到消息”事件。拖出该事件块,并在块内添加一些代码块,看看当你收到短信时,会发生什么事情。在本章的例子中, 我们希望自动回复一条预先设定好的信息。
用三行代码块就可以实现短信的发送:①设置接收短信的电话号码,即设置短信收发器组件的电话号码属性;②设置将要发送的短信内容,这也是短信收发器组件的一个属性;③使用短信收发器组件的发送消息功能发送短信(术语:调用短信收发器组件的发送消息过程。——译者注)。表4-2列出了自动回复功能所需要的代码块,图4-3是这些代码块在编程视图中的排列。
表4-2 实现自动回复功能的代码块
手机收到短信时,将触发短信收发器1的收到消息事件。如图4-3所示,发送者的手机号保存在参数手机号码中,短信的内容保存在参数消息内容中。
自动回复就是要向发送者发送一条短信,为此要先设置短信收发器组件的两个关键属性:电话号码及短信。将电话号码属性设置为发送者的手机号码,短信属性设置为回复内容标签中显示的内容:“我正在开车,稍后与您联系。”设置完成之后,执行短信收发器1的发送短信指令,来实现自动回复。
测试:需要用两部手机来测试程序,第一部用于运行这个应用,第二部用来向第一部发送短信。如果只有一部手机,可以在电脑上使用Google Voice或其他类似的服务,利用这些服务给运行应用的手机发送短信。设置完成后,给正在运行本应用的第一部手机发短信,看看第二部手机是否收到了回信?
编写自定义回复内容
下面来添加更多的程序块,允许用户输入自定义的回复内容。在设计视图中,已经添加了名为自定义短信输入框组件,用于输入自定义回复信息,当用户点击保存按钮时,自定义短信输入框中的内容将显示在回复内容标签中,成为自动回复短信的内容。表4-3列出了在回复内容标签中显示自定义回复内容所需要的块。
表4-3 显示自定义短信所需要的块
块的作用
一个典型的输入表单的工作流程是:首先在文本框中输入文字,然后单击保存按钮来通知系统做处理,本应用中的输入表单也不例外。图4-4显示了用户点击保存按钮时触发的点击事件处理程序。
测试:输入一段自定义信息并点击保存按钮,然后用第二部手机发送短信到测试手机上,看看这次自动回复的是新的自定义内容吗?
永久保存自定义回复内容
现在用户可以自定义短信内容,来实现自动回复功能,不过这里有一个小问题:用户输入了自定义回复内容,然后关闭应用,当再次启动应用时,自定义的内容却不见了(取而代之的是默认的回复内容)。这可不是用户想要的功能,他们希望在重新启动应用时,自定义的内容还在,为此需要信息的永久保存。
在回复内容标签的显示文本属性中保存数据,从技术上讲,也算是一种数据的存储,只不过是一种临时存储。临时存储类似于人类的短时记忆,只要应用关闭,数据就会被“忘记”。如果希望应用能永久记住某些数据,就需要将临时存储的数据(组件的属性或变量)转变为永久存储的数据(数据库或文件)。
要永久地保存数据,本章要用到本地数据库组件,它可以将数据存储在安卓设备内置的数据库中。本地数据库组件有两个最常用的功能:保存数据和请求数据。前者允许应用将信息存储在设备数据库中,而后者则允许应用重新读取已存储的信息。 对于大多数的应用,都可以采取如下存储策略:
- 当用户提交新的数据时,将其存储到数据库中;
- 在应用启动时,从数据库中加载数据,并将其保存在一个变量或组件的属性中。 为了实现数据的永久保存,必须修改保存按钮的点击事件处理程序,表4-4中列出了所需要的代码块。
表4-4 用本地数据库组件保存自定义短信内容所需要的块
块的作用
使用本地数据库组件保存数据需要提供两个参数:需要保存的数据,以及存储数据时使用的标记。从回复内容标签的显示文本属性中提取要保存的数据,使用“自定义短信”为标记,将数据保存到数据库中。如图4-5所示。可以把标记想象成数据在数据库中的存放地址,是数据的唯一标识。在下一节中你将看到,在从数据库中提取数据时,必须使用相同的标记(“自定义短信”)。
将自定义短信保存在数据库中,以便用户再次启动应用时,保存的数据可以被重新读取出来。App Inventor可以侦测到一个特殊的事件:屏幕初始化事件,当应用启动时,将触发该事件(我们在第3章打地鼠中使用过)。将“当Screen1初始化时”块拖出来,并将一些代码块放在其中,那么这些代码块会在应用启动时按顺序执行。
在本应用中,将在Screen1的初始化事件中检查数据库中是否存放了自定义短信。如果是,则使用本地数据库组件的请求数据指令加载存储的内容。实现这一功能所需的块见表4-5。
表4-5 应用启动时用于加载数据的块
块的作用
如图4-6所示,要想理解这些块的功能,必须设想用户的使用过程:首次打开应用,用户输入自定义短信,随后退出应用,然后再次打开应用。用户首次启动应用时,数据库中没有自定义短信可供提取,因此回复内容标签中显示的是默认回复。再次启动时,才有可能从数据库中提取到自定义短信,并将其显示在回复内容标签中。
不过,第一次启动应用时,数据库中没有数据,只有当用户输入了自定义短信,并点击保存按钮时,数据才被保存到数据库中。本地数据库组件的请求数据过程的第二个参数“无标记返回”,就是为了处理这种没有数据的情况而设置的,即,如果没有发现可提取的数据,则返回预先设定的无标记返回值,在这个例子中,返回默认的回复内容:“我正在开车,稍后与您联系。”,并将其显示在回复内容标签中。
测试:要测试这个新功能,需要重新启动应用,以便察看数据是否保存成功,并且能否被重新提取出来。在实时测试状态下,有一个办法可以重新启动应用,就是在设计视图中修改某个组件的属性值,如修改某个标签的字号,这种修改会导致测试设备中应用的重新启动,并触发屏幕初始化事件。当然,你也可以将应用编译成.apk文件并安装到手机上,进行正式测试。应用在手机上安装运行后,输入并保存自定义信息,然后关闭应用;紧接着再打开应用,此时,如果还能看到你保存过的信息,则测试成功。
大声读出收到的短信
本节为应用添加新的功能:收到短信后,手机将大声读出短信发送者的电话号码以及短信内容。开车时收到短信,虽然有了自动回复功能,但你还是禁不住想知道来信的内容。使用安卓设备的语音合成功能,就可以在手不离方向盘的情况下,收听短信的内容。
安卓设备提供了语音合成功能,而App Inventor提供了一个语音合成器组件,它可以读出任何提交给它的文本信息 。注意:语音合成器组件读出的文本信息指的是一串字母、数字及标点符号组成的文本,而不是手机之间收发的短信。
语音合成器组件简单易用,只需调该组件的用合成语音功能,并给出需要读出的文字即可,如图4-7所示,在合成语音的代码块中,将一段文字,如“你好,世界!”填充到消息参数的插槽中,即可让安卓设备读出这段文字(前提是你事先安装了讯飞语音+,见本章的注脚4。如果尚未安装,请用“Hello World!”替代“你好,世界!”进行测试。——译者注)。
需要回到之前的短信收发器1的收到消息事件中,调用语音合成器1的合成语音功能。此前,在收到消息事件中,我们实现了短信自动回复功能:设置短信收发器的电话号码及短信属性,并发送设定好的短信。现在需要添加表4-6中所列出的块来扩展该事件的处理程序。
表4-6 读出收到的短信所需的块
块的作用
在自动回复动作完成之后,将调用语音合成器1的语音合成功能,如图4-8的下半部分所示。你可以在合成语音块的消息插槽中插入任何文字。在这个例子中,“拼字串”块用来拼接需要被读出的内容,它将“收到来自”、来信号码、“的短信,内容是:”以及来信内容这四段文字串连在一起。假设收到来自1111-222发来的短信“你好!”,则最后将生成这样的信息:“收到来自1111-222的短信,内容是:你好!”。
在自动回复中加入位置信息
签到类的应用(Check-In) 可以帮助人们追踪彼此的位置信息,但这类应用最令人担忧的是隐私问题,原因之一是它引发了人们对“老大哥”的恐惧,这里的“老大哥”指的是那些设法跟踪其公民下落的集权政府。但是使用位置信息的应用的确非常有用,试想一个迷路的小孩,或者那些在森林里迷路的徒步旅行者。
在“开车不发短信”的应用中,位置跟踪让回复的短信再多一点内容,而不只是“我正在开车”,回复的信息可以是这样的:“我正在开车,我的位置是北京东直门内大街1号。”对于那些正在等待朋友或家人到来的人来说,这些额外的信息非常有益。
App Inventor提供了位置传感器组件,作为手机GPS (Global Positioning System全球定位系统)功能的接口。除了纬度和经度信息,位置传感器组件也可以接入到谷歌地图,为司机提供当前位置的地址信息 。
这里需要说明一下,位置传感器组件并不是连续地读取位置信息,在两次读取信息的动作之间,有一定的时间间隔,这是使用这一组件需要注意的地方。也就是说,手机位置的改变并不能直接触发位置信息改变事件,只有当传感器读取到新的位置信息时,才能触发位置信息改变事件,我们所要做的是,在应用中对位置信息改变事件作出响应。有两种情况会触发位置信息改变事件:①当传感器第一次收到位置信息时;②随着手机的移动,传感器读取到了新的位置信息时。表4-7中列出了响应该事件需要的块。如图4-9所示,声明一个全局变量“当前位置”,将传感器最后一次收到的位置信息保存在变量中,此后,当手机收到短信时,将该位置信息整合到自动回复信息中。
表4-7设置位置传感器的块
当位置传感器首次读取位置信息时,将触发位置传感器组件的位置信息改变事件,随着设备的移动,传感器将读取到新的位置信息,事件将被再次触发。当事件发生时,将最新的位置信息(带有街道及门牌号的具体地址)保存在变量“当前位置”中。
以上代码只是用于获取位置信息,距离我们的最终目标——将位置信息编排在自动回复短信中,还差一步,下面继续努力。
发送带有位置信息的回复短信
修改短信收发器1的收到消息事件处理程序,利用变量当前位置中保存的地址信息,生成自动回复信息。表4-8种列出了所需的块。
表4-8 在自动回复中添加位置信息所需的代码块
块的作用
向回复短信中添加的位置信息来自于全局变量当前位置,而当前位置来自于位置传感器1的位置信息改变事件,现在来使用这段位置信息。在图4-10中,不是简单地发送回复内容标签中的文字,而是使用“拼字串”块将若干段信息整合起来:原有的自动回复信息 +“ 我的最新位置是:”+ 当前位置 。
测试:用第二部手机发送短信到运行应用的手机上,第二个手机是否接收到了带有位置信息的自动回复?如果没有,请确保你已经开启了第一部手机的GPS定位功能。
完整的应用:开车不发短信
图4-11中显示了“开车不发短信”中所有的代码块。
改进
一个应用,如果你每天都在用,你总会发现它有不尽人意之处,之后便开始逐步完善它,这个应用也不例外,例如下面的改进:
- 添加更为个性化的功能,允许用户针对某些特定来信号码定制回复内容。你需要增加一个条件(如果)块,来判断这些来信的手机号。有关条件(如果)块的更多信息,请参见第18章;
- 提高定位的精确程度:根据用户是否在某个纬度/经度范围内,来确定用户的精确位置,并定制相应的回复信息。例如,如果应用判断你在房间222,它会回复“李四在222房间,现在不能回复短信。”有关位置传感器组件以及边界定位的更多信息,请参见第23章;
- 还有一种改进,针对某些特殊的来信号码,发出特殊的提示铃声,可以将这些特殊号码放在一个“通知”列表中,以便收到短信时进行判断。关于如何使用列表,请参阅第19章。
小结
下面是本章涉及到的一些概念:
- 短信收发器组件:既可以用来发短信,也可以处理收到的信息。在执行发送消息指令之前,需要为短信收发器组件设置电话号码及短信属性。为了对收到的信息进行回复,需要为短信收发器组件编写收到消息事件处理程序;
- 本地数据库组件:用于将信息永久存储在手机数据库中,以便每次应用启动时都可以加载保存过的数据。有关本地微数据库组件的更多信息,请参见第22章;
- 语音合成组件:对于所提供的任何文本信息,都可以大声地读出来(读中文需要手机中安装讯飞语音+,并做相应的设置。——译者注);
- 拼字串:用于将若干个文本片段拼凑(或连接)成一整段文字;
- 位置传感器组件:可以报告手机的纬度、经度及当前的街道地址。为了确认它是否收到了位置信息,可以从位置传感器组件的位置信息改变事件中获取相关的参数。该事件在第一次收到位置信息时被触发,并在每次位置信息更新后被再次触发。有关位置传感器组件的更多信息,请参见第23章。
本文来自投稿,不代表本站立场。作者:17coding,如若转载,请注明出处:《App Inventor编程教程-第5课-开车不发短信》https://www.shaoerbc.org/code-course/appinventor-course/749.html