天天看点

《Android应用开发攻略》——1.15 程序:Android OS下的小费计算器Tipster

sunit katkar

1.15.1 问题

当你和朋友前往饭店就餐并且希望计算各自的账单和小费时,可能陷入许多手动计算和分歧之中。你希望使用一个应用程序,简单地将小费比例加到总额上,并且按照就餐人数分配。tipster就是android中的一个实现,用它展示一个完整的应用程序。

1.15.2 解决方案

这是一个简单的练习,使用android中的基本gui元素,然后用一些简单的计算和事件驱动ui代码将它们组合起来。将用到如下gui组件:

tablelayout

该组件很好地提供了对屏幕布局的控制。可以使用html的table标记来设计窗口部件。

tablerow

这个组件定义了tablelayout中的一行。类似于html tr和td标记的组合。

textview

这个view子类为屏幕上显示的静态文本提供标签。

edittext

这个view子类提供输入用的文本字段。

radiogroup

组合单选按钮。

radiobutton

提供单选按钮

button

常规按钮。

view

将使用view创建具有特定高度和颜色属性的视觉分隔符。

1.15.3 讨论

android用xml文件来设计窗口部件的布局。在示例项目中,eclipse的android插件生成用于布局的main.xml文件。该文件包含基于xml的不同窗口部件及其容器的定义。

strings.xml文件包含应用程序中的所有字符串资源。默认的icon.png文件用于应用程序图标。

然后是自动生成的r.java文件(修改main.xml时将会更新)。这个文件包含为每个布局和窗口部件定义的常量。不要手动编辑该文件;当修改xml文件时,插件会自动进行相应的修改。

在例子中,tipster.java是用于activity的主java文件。

攻略1.4和各种google教程强调了该插件的使用方法。使用eclipse插件,创建android项目tipster。最终的结果将是外观类似于图1-39的项目布局。

创建布局并放置窗口部件

本攻略的最终目标是创建一个类似于图1-39的布局。

对于这个屏幕布局,将使用如下布局和窗口部件:

提供对屏幕布局的控制。这个布局使用html table标记范例来设计窗口部件的布局。

定义tablelayout中的行,类似于html tr和td标记的组合。

这个view子类提供输入数值的文本字段。

提供单选按钮。

使用view类创建具有特定高度和颜色属性的视觉分隔符。

因为你所构建的应用程序中将大量使用这些窗口部件,所以要自己动手熟悉它们。当你查看布局和窗口部件的javadoc时,仔细观察xml属性。这将帮助你建立main.xml布局文件中的用法与访问该文件的java代码(tipster.java和r.java)之间的关联。

eclipse adt还有一个可视化布局编辑器,以及单独的ui工具droiddraw,这两者都可以通过从工具面板上拖放窗口部件来创建布局,就像所有表单设计工具一样。但是,我建议你手动地在xml中创建布局,至少在android的初学阶段要这么做。以后,当你学习到xml布局api的微妙之处,可以将这一任务交给上述工具。

布局文件main.xml包含布局信息(见例1-6)。tablerow部件在tablelayout中创建一行,可以使用任意多个tablerow。在这个教程中,将使用8个tablerow,其中5个用于按钮下面视觉分隔符之上的窗口部件,另外三个用于按钮和分隔符之下的结果区域。

例1-6:/res/layout/main.xml

tablelayout与tablerow

研究main.xml之后,你会发现tablelayout和tablerow的使用很简单:创建tablelayout,然后插入tablerow。现在,可以自由地在tablerow中插入任何其他窗口部件,例如textview、editview等。

仔细观察属性,特别是android:stretchcolumns、android:layout_column和 android:layout_span,可以用这些属性,按照使用常规html表格的方法放置窗口部件。我建议你关注这些属性的链接,研究它们对tablelayout的影响。

控制输入值

控制输入值:查看main.xml文件中①处的edittext部件。这是第一个文本输入字段,用于输入账单“总额”,只允许输入数字。可以接受小数,因为真正的饭店账单都包含元和分,而不仅仅是元。所以将android:numeric属性值类型设置为decimal。这样,该输入字段中允许输入整数值(如10)和小数值(如10.12),而不允许其他任何类型的输入。

这是简单明了的输入值控制方法,可以省去在tipster.java文件中编写验证代码的麻烦,确保用户不会输入不正确的值。android基于xml的约束功能相当强大而实用。你应该研究特定窗口部件的所有可能属性,从设置约束的xml快捷方法中获得最大的益处。除非我在这个版本中完全没有用到,否则我希望在未来的版本中,android能考虑在android:numeric加入范围,便于我们定义接受的数值范围。

因为(据我所知)目前还没有范围属性,以后你将会看到,我们必须检查特定的值(如0或者空值),以确保小费计算不会失败。

分析tipster.java

现在,我们来看看控制应用程序的tipster.java文件。这是一个主类,完成布局、事件处理和应用程序逻辑。

android eclipse插件在项目中创建tipster.java文件的默认代码如例1-7所示。

例1-7:/src/com/examples/tipcalc/tipster.java的代码段1

tipster类扩展了android.app.activity类。活动(activity)是用户所能进行的单一中心工作。activity类负责窗口的创建和ui布局。必须调用setcontentview(view view)方法将ui放入activity中。所以可以将activity看做空的外部框架,然后填入你的ui。

现在看看例1-8中的tipster.java类片段。首先定义作为类的成员窗口部件。仔细研读这一例子①到②的部分,作为以后的参考。

然后,用findviewbyid(int id)方法定位窗口部件。当在eclipse中清理并构建项目时,在main.xml文件中定义的每个部件id自动在r.java文件中定义。(如果将eclipse设置为自动构建,当更新main.xml时,r.java文件立刻更新)。

每个窗口部件都从view类继承而来,提供特殊的gui功能。textview类提供了在ui上放置标签的手段,而edittext则提供了一个文本字段。查看例1-8中③~⑥对应的部分,你可以看到如何使用findviewbyid()寻找窗口部件。

例1-8:/src/com/examples/tipcalc/tipster.java的代码段2

解决易用性或者可用性问题

应用程序必须达到其他已经发布的应用程序或者网页的易用性水平。简而言之,增加易用特性能够带来好的用户体验。为此,再次查看例1-8。

关注使用view类的requestfocus()方法的地方④。因为edittext部件继承自view类,该方法适用于它。因此,当应用程序加载时,总额(total amount)文本字段将得到焦点,光标出现在该控件中。这与流行web应用程序的屏幕登录相似——在登录屏幕中光标出现在用户名文本字段中。

现在再看看calculate(计算)按钮⑤,通过调用button部件上的setenabled(boolean enabled)将它禁用。这样,用户在输入必要的字段值之前,用户无法单击它。如果在总额和人数字段未输入值的情况下允许用户单击calculate按钮,就必须编写捕捉这些情况的验证代码,从而必须向用户显示有关空值的弹出式警告,这会增加不必要的代码和用户交互。当用户看到calculate按钮禁用时,就能很明显地看出,除非输入所有值,否则小费无法计算。

在例1-8中的⑦,这里还禁用了other tip percentage(其他的小费比例)文本字段。这是因为应用程序加载时默认选中“15% tip”单选按钮,这一默认选择通过main.xml文件完成。main.xml中用如下的语句选择了“15% tip”单选按钮:

radiogroup属性android:checkedbutton允许选择组中默认的一个radiobutton部件。

使用过流行桌面和web应用程序的大部分用户都熟悉“disabled widgets enabled on certain conditions”(在某种条件下启用已经禁用的部件)范例。增加这种小的便利功能总是能使应用更加易用,用户体验也更加丰富。

处理ui事件

和流行的windows、java swing、 flex和其他ui框架一样,android也提供了事件模型,可以监听ui中由用户交互引起的事件。我们来看看如何在应用中使用android事件模型。

首先关注ui中的单选按钮。我们希望知道,用户选择了哪一个单选按钮,因为这能够确定应用程序中的小费比例。使用静态接口oncheckedchangelistener()“监听”单选按钮,当按钮选择状态变化时将会得到通知。

在应用程序中,希望在选中other(其他)单选按钮时才启用other tip percentage文本字段。当“15% tip”和“20% tip”单选按钮选中时,我们希望禁用文本字段。除此之外,还要添加一些有利于易用性的逻辑。之前已经讨论过,不应该在必要的所有字段中输入有效值之前启用calculate按钮。对于这三个单选按钮,应该确保在如下两个条件下启用calculate按钮:

other单选按钮选中,且other tip percentage文本字段输入了有效值。

“15% tip”或“20% tip”单选按钮选中,且total amount和no. of people文本字段输入了有效值。

例1-9中对单选按钮进行了处理。源代码注释已经做出了很好的解释:

例1-9:/src/com/examples/tipcalc/tipster.java的代码片段3

监控文本字段中的键盘活动

前面已经提到,除非文本字段输入了有效值,否则calculate按钮不能启用。因此,必须确保calculate按钮仅在total amount、no. of people和other tip percentage文本字段中输入有效值之后启用。other tip percentage文本字段仅在选中other tip percentage单选按钮时启用。

我们不必担心输入值的类型、用户是否输入负数或者字母,因为android:numeric属性已经定义了文本字段,限制了用户所能输入的类型。只需要确保输入值存在。

使用静态接口onkeylistener(),该接口在按下键时通知我们。通知在实际按键发送到edittext部件之前就会到达。

例1-10和例1-11处理文本字段中的按键事件。和例1-9中一样,源代码中的注释也很好地解释了代码的功能。

例1-10:/src/com/examples/tipcalc/tipster.java的代码片段4

注意,只创建一个监听器,而不是为每个文本字段都创建匿名/内部监听器。我不确定自己的风格更好或者值得推荐,但是如果监听器将要执行一些公用的操作,我就总以这种风格编写代码。所有文本字段都有公共的一个关注点:它们都不应该为空,只有在它们有非空值时,才应该启用calculate按钮。

例1-11:代码片段5,摘自keylistener.java

在例1-11的①处,检查view类的id。记住,因为在main.xml文件中的定义,每个窗口部件都有唯一的id。之后,在生成的r.java类中定义了这些值。

在②和③处,如果总金额或者人数字段中发生了键盘事件,将检查字段中输入的值,确保用户对这两个字段都没有留空。

在④处,检查用户是否选择other单选按钮,然后确定other文本字段不为空。还要再次确定金额或者人数字段是否为空。

keylistener的目的现在很清晰了:确保所有文本字段非空,仅在这种情况下启用calculate按钮。

监听按钮单击

现在来看calculate和reset(复位)按钮。我们使用静态接口onclicklistener()来通知用户何时单击这些按钮。

和文本字段一样,只创建一个监听器,在监听器中检测被单击的按钮。根据单击的按钮,调用calculate() 或reset()方法。

例1-12说明了为按钮添加单击事件监听器的方法。

例1-12:/src/com/examples/tipcalc/tipster.java的代码片段6

复位应用程序

当用户单击reset按钮时,文本字段应该清除,选中默认的“15% tip”单选按钮,应该清除所有计算结果。

例1-14展示了reset()方法。

例1-14:/src/com/examples/tipcalc/tipster.java的代码片段8

验证计算小费的输入

前面已经提到,我们限制了文本字段中用户所能输入的值的类型。但是,用户仍然可以在总金额、人数和其他小费比例字段中输入0值,这会造成计算中除以0等错误。

如果用户输入0,必须显示一个弹出式警告框,要求用户输入非0值。用showerroralert(string errormessage, final int fieldid)方法处理这一任务,稍后将对此进行更详细的讨论。

首先,看看例1-15中展示的calculate()方法。注意用户的值是如何解析为双精度值的。

现在注意①和②中对0值的检查。如果用户输入0,显示一个弹出警告框对用户加以警告。接下来看看③,因为用户选择了other单选按钮,所以other tip percentage文本字段启用,还必须检查小费率是否为0。

当应用程序加载时,默认选中“15% tip”单选按钮。如果用户改变了选择,将选中的单选按钮id赋值给成员变量radiocheckedid,正如在例1-9的oncheckedchangelistener中看到的那样。

但是,如果用户接受默认选择,radiocheckedid将为默认值-1。简而言之,我们永远不会知道选中的是哪一个单选按钮。当然,我们知道默认选中的是哪一个按钮,可以编写稍有不同的逻辑,如果radiocheckedid的值为-1就假定小费比例为15%。但是,如果查阅api,你就会发现:可以在radiogroup上而不是在单独的单选按钮上调用getcheckedradiobuttonid()方法。这是因为oncheckedchangelistener提供了选中的单选按钮的id。

显示结果

计算小费很简单。如果没有验证错误,布尔标志iserror将为false。简单的小费计算参见例1-15的④~⑤。接下来,计算出的值将在⑥~⑦中设置到textview窗口部件。

例1-15:/src/com/examples/tipcalc/tipster.java的代码片段9

显示警告

android提供alertdialog类来显示弹出式警告。可以用它显示一个具有多达3个按钮和一条信息的对话框。

例1-16展示的showerroralert方法使用alertdialog显示错误消息。注意,向这个方法传递了两个参数:string error message和int fieldid。第一个参数是我们希望向用户显示的错误消息。fieldid是导致错误的字段id。在用户关闭警告对话框之后,这个fieldid使我们能够将焦点置于该字段之上,用户由此得知该字段发生了错误。

例1-16:/src/com/examples/tipcalc/tipster.java的代码片段10

组合以上各个功能,就实现了图1-39中的效果。

《Android应用开发攻略》——1.15 程序:Android OS下的小费计算器Tipster

结语

android os的开发与其他ui工具包的开发(包括microsoft windows、 x windows、 java swing或adobe flex)没有太大的不同。当然,android也有自己的特点,总体上是一个非常好的设计。xml布局范例相当好,可以用简单的xml构造复杂的ui。此外,事件处理模型很简单、具有丰富的特性,在代码中使用也很直观。

1.15.4 源代码下载url

可以从<code>http://www.vidyut.com/sunit/android/tipster.zip</code>下载上述例子的源代码。

1.15.5 二进制文件下载url

可以从<code>http://www.vidyut.com/sunit/android/tipster.zip</code>下载上述例子的二进制文件。