简介:Activity
类是 Android 移动应用程序的基础,您可以使用它来优化应用程序与用户和移动设备的交互。让应用程序生命周期中的交互方式与您的期望完全一致,并使用图标与操作栏引导用户使用
UI 导航与其他应用程序功能。
如今移动设备的功能已经强大到难以置信,比众多开发人员用来编写首个程序的桌面计算机还要强大得多。因此,大家很容易忘记移动设备仍然属于资源有限的环境。开发移动应用程序时,决不能忘记运行应用程序的环境所具有的局限性。尤其是当应用程序要与其他应用程序竞争系统资源时
— 其中有些应用程序对于用户的日常行为而言比您的应用程序更加重要。
确保应用程序广受欢迎的途径之一是保证它节省系统资源。在 Android
中,使用和保持系统资源的机制都是 Activity 类。您越了解这个基本类(与 Java Servlet
十分相似)的生命周期,调整 Android 移动应用程序的资源使用与性能的能力就越强。
我们将从快速了解 Activity 类生命周期开始。通过一个示例应用的演示,您将了解处理
Android 应用程序生命周期内每个阶段的方法。掌握这些方法协同工作的原理之后,就能聪明地使用系统资源。然后更新演示应用程序的导航系统,使用
操作图标 代替菜单按钮来实现用户交互。图标在移动应用程序 UI 中是十分标准的,而较新的 Android
设备(版本 4.2.2 及更高的版本)已经弃用了选项菜单,而改用操作栏。掌握如何将这些特性与您的 Android
移动应用程序集成在一起将使您受益无穷!
Activity 类生命周期
Activity 的生命周期直接对应着 Android 移动应用程序的生命周期。当用户与应用程序或运行应用程序的设备进行交互时,Android
平台将在 Activity 实例上执行回调。当用户启动应用程序时,初始的 Activity 将执行一个已定义的生命周期。当应用程序转入后台时,它执行生命周期的一个不同阶段,而当应用程序关闭时则执行另一个阶段。图
1 显示了每个交互阶段的 Android Activity 生命周期。
图 1. Android 的 Activity
生命周期
Android 移动应用程序生命周期包含四个阶段:
1.启动
2.暂停与恢复
3.停止与重启
4.销毁
后面的内容将会讲述每个阶段及其回调方法(可在 Activity 实例内部实现)。
Activity 生命周期中的启动
演示应用程序
如果您一直关注本系列文章,那么在本系列的第一和第二篇文章中已经创建了自己的演示应用程序。如果没有演示应用程序,建议您在继续之前创建一个。另外,您还可以复制我自己的
Overheard Word 演示应用程序的 Git 库(参见 参考资料)。
在 前面的文章中,您已经使用了对应启动 Activity 的回调方法,即
onCreate。您可能也熟悉 onStart 与 onResume,启动时也会调用这两个方法。现在,在
Activity 生命周期的上下文中考虑这些方法。
在 Eclipse Android 开发环境中,选择 Override/Implement
Methods... 选项即可轻松重写方法,如 图 2 中所示。
图 2. 重写 Activity 生命周期回调方法
接下来,选择 onStart 与 onResume 方法:
图 3. 选择回调
现在使用 Android 的 Log 类加入一些跟踪语句,就像我在 清单
1 中所做的那样。
清单 1. 实现 Android Activity 回调
@Override protected void onResume() { super.onResume(); Log.d("overheardword", "onResume Invoked"); }
@Override
protected void onStart() {
super.onStart();
Log.d("overheardword", "onStart
Invoked");
} |
启动应用程序的一个实例并通过 LogCat 查看日志,对结果进行检查,如
图 4 中所示。
图 4. LogCat 的调试语句
Android 使用 LogCat 记录日志
Android 拥有自己的日志记录系统 android.util.Log。借助这个方便的类,您可以记录各种水平(比如
info、warn、debug 等)的日志,然后通过 Android SDK 自带的 logcat 工具查看日志。在
Eclipse 中,您应该将 LogCat 看作一个选项卡,可以使用它过滤标签和应用程序实例。LogCat
还支持在设备上访问日志,只要将设备插入台式机或笔记本电脑的 USB 插口即可。
您很可能已经猜到,首次加载应用程序时将调用 onCreate,而在其他阶段的上下文中使用
onStart 与 onResume 更加方便,比如当应用程序转入后台和重启时。
Activity 生命周期中的暂停与恢复
因为移动设备通常会运行多个应用程序,而它们会以各种方式来吸引用户的注意力,因此您的应用程序应该知道何时让另一个应用程序占据设备屏幕并使用更多资源。有时,用户在使用应用程序时需要接电话,或者是应用程序可能会弹出一个对话框,比如信息请求或错误消息。上述每种操作都将部分地阻断当前的
Activity。
当一个 Activity 被部分阻断时,将调用 onPause 方法。当暂停的
Activity 重新获得焦点时,将调用 onResume。暂停与恢复表示受影响的活动被部分阻断,而非完全隐藏。
当应用程序完全隐藏时,例如用户打电话,还会调用 onPause,但在这种情况下还会继续调用
onStop。当应用程序再次转入前台时,将先调用 onRestart,再调用 onStart,最后调用
onResume。
下面解释实现 onPause、onRestart 与 onStop 时发生的事情。如果您已经有了本系列文章中使用的
Android 应用程序,那么在代码中添加一些日志语句,然后运行应用程序。按下 Home 按钮完全隐藏实例,然后单击它的图标再次运行。您应该看到调用了一系列方法。首先看到的是
onPause,然后是 onStop。 单击图标重新运行应用程序时,调用的方法依次是 onRestart、onStart
和 onResume。
销毁 Activity 也是运行应用程序的常规过程中会发生的事情。例如,可以调用
Activity 实例的 finish 方法来终止该实例。这里的关键在于,因为关闭了一个 Activity,所以它将遵循与被隐藏相同的生命周期,但它最后会回调
onDestroy。
在 清单 2 中,我使用自己的 Overheard Word 应用程序(参见
“面向大众的移动技术:轻轻一划!” 或从 Github 获取资源)演示了这个过程,具体做法是在向上划动手势时调用了
finish 方法。
清单 2. 销毁 Activity 实例
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { try { final SwipeDetector detector = new SwipeDetector(e1, e2, velocityX, velocityY); if (detector.isDownSwipe()) { return false; }else if (detector.isUpSwipe()) { finish(); }else if (detector.isLeftSwipe()) { Toast.makeText(getApplicationContext(), "Left Swipe", Toast.LENGTH_SHORT).show(); }else if (detector.isRightSwipe()) { Toast.makeText(getApplicationContext(), "Right Swipe", Toast.LENGTH_SHORT).show(); } } catch (Exception e) { // nothing } return false; } |
最常用的 Activity 生命周期方法是 onCreate、onRestart
与 onDestroy。例如,我使用了 onRestart 来刷新应用程序 UI 视图的众多方面之一,并使用
onDestroy 释放到数据库的连接,比如 Android 设备上本地运行的 SQLite。
现在可能还不明显,但一旦开始与外部资源协作 — 比如外部 Web 服务或设备的文件系统或数据库
— 这些生命周期阶段将变得十分重要。
接下来解释如何使用两个 Activity hook 方法 — onCreateOptionsMenu
与 onOptionsItemSelected — 实现应用程序菜单行为。让这两个方法同步后,我们将把它们的功能连接到图标,以实现额外的
UI 效果。
使用菜单与动作进行导航
当我在 Eclipse 中创建 Overheard Word 项目时,定义的第一个
Activity 有一个存根方法 onCreateOptionsMenu。正如您猜想的那样,此方法用于创建一个选项菜单。在老式的
Android 设备上,选项菜单由 Menu 按钮表示。在较新的设备上,它被表示为一系列垂直的点,显示在应用程序本身之中。较新的
Android 设备不一定有菜单按钮。
在表示老式设备的模拟器实例中,有一个名为 "Menu"
的按钮。只要单击它,应用程序实例就会显示选项菜单。在这个例子中,我们将看到用于导航的选项。例如,如果用户按下
Home 按钮,就会看到如 图 5 中所示的内容。
图 5. 一个未实现的菜单项
平板电脑上没有菜单按钮。用户无法从 菜单 中选择项目,而是被要求发起各种
操作。这个较新的 UI 栏称为 操作栏,如 图 6 中所示。
图 6. Android 的新操作栏
尽管菜单按钮与操作栏的行为方式很类似,但操作栏只在较新的设备上能实现。由于我们的目标是老版本的
Android 系统(记住,约有 50% 的 Android 设备运行 Gingerbread!),因此我将使用更加熟悉的菜单按钮进行演示。稍后,我将说明如何更新导航代码以实现操作栏,满足您以较新版本的
Android 及对应设备为目标的愿望。
创建一个选项菜单
为了翻新 Overheard Word 以提高用户交互的效率,第一步最好是实现选项菜单,让用户能退出应用程序。退出应用程序是
Activity 生命周期的阶段之一,因此我们将使用 Activity 方法实现这个功能。
记住,在 Android 应用程序中,所有与 UI 相关的业务都对应一个
XML 文件,因此定义 UI 的方法就是编辑布局的 XML 文件。Android 应用程序的 XML 文件位于项目的
res 文件夹的特定目录中(例如,布局文件位于 layout 目录中)。
为了快速进行练习,可以看一看 Overheard Word 主活动中 onCreateOptionsMenu
方法的默认实现方法 — 您看出了什么门道?
public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.overheard_word, menu); return true; } |
如果您正在考虑查找 menu 资源目录中一个名为 overheard_word.xml
的 XML 文件,那么您就离成为一名 Android 专家不远了!
我... 退出!
接下来,我们将编辑菜单资源 XML 文件,添加一个名为 quit 的菜单项。一开始需要在您的
res/values 目录中找到 strings.xml 文件。找到之后,创建一个如下所示的新项:
<string name="quit_menu">Quit</string>
这个标记定义了单词 Quit,可以通过标识符 quit_menu 来引用它(顺便说一句,这对于应用程序的国际化很有好处)。接下来,打开
menu 目录中的 overheard_word.xml 文件。 在这个文件中,将标题修改为 @string/quit_menu,从而将单词
Quit 链接到菜单项。
现在,启动模拟器并按下 Menu 按钮。应该看到一个菜单出现在屏幕下方,其中有一个选项:Quit。但选择它什么效果也没有,因为目前还没有实现它。
我们将在一分钟内为 Quit 选项添加实现代码。但首先,我们要考虑移动应用程序的任意功能部分的另一重要元素,即它的外观。您可能已经注意到,如今大量移动
UI(甚至越来越多的 Web 应用程序 UI)都使用图标进行导航。下面将说明如何使用免费图标替换通用词按钮。
移动 UI 设计中的图标
在进入移动开发领域之前,我对图标也有涉猎,但很少在我的企业应用程序中使用它们。当
Web 应用程序的交互性开始变得更加突出时,我发现自己使用图标的次数也在增加。但直到我开始从事移动开发,图标才真正成为我的工作重点。
我的图标在哪里?
如今,要寻找在开源与商业应用中使用的免费图标是件很容易的事。您还可以支付一点点费用,购买某些图标的使用权。我个人喜欢一个名为
Glyphish 的包(参见 参考资料),其中包含数百个图标可供选择,而且许可费用非常合理。Glyphish
还提供一个免费的许可证。建议您快速搜索和查找希望在本文中用于演示的图标。
如果在 Android 移动 UI 设计中使用图标,需要充分了解设备的分辨率。Android
设备生态系统非常庞大,您的应用程序可能需要在各种设备上运行,从低分辨率的小屏设备一直到配备 7 英寸大屏的高分辨率平板电脑。一个在手持设备上显示效果良好的图标,在平板电脑上可能显得十分粗糙。
幸运的是,您可以控制应用程序图标在不同设备上的外观。快速访问 Android
移动应用程序的 res 目录。您应该可以看到一些名为 drawable-something-pdi 的目录(这里的
"something" 是任意字母序列)。这些目录对应各种设备屏幕的分辨率。在这些目录中放置大小正确的图标与其他图像文件,可以确保您的图标在不同类型的设备上正确显示。
例如,对于分辨率超高的设备,Android 将使用 drawable-xxhdpi
目录中的图标。此目录中的启动图标应该为 96 x 96 像素,并且至少为 320 dpi。drawable-ldpi
目录中的启动图标应该为 36 x 26 像素和 120 dpi。您也可以选择创建一个默认的 drawable
目录,当 Android 无法找到指定图标分辨率对应的文件时,将使用此目录下的图标。
为了简单起见,我将为我的 Overheard Word 应用程序创建一个
drawable 目录。我在此目录中放置一个 26 x 26 的图标文件(.png 格式),用于退出选项。
图 7. 为 drawable 目录添加一个图标
我的下一个步骤是在选项菜单中引用该图标,具体做法是在我的 overheard_word.xml
文件中更新 menu 项,如下所示:
android:icon="@drawable/quit_icon"
如果您严格遵循我的步骤,则应更新同一元素的 id。为它指定一个描述性的字符串值,如下所示:
android:id="@+id/quit_item"
进行下一个步骤,即在 onOptionsItemSelected 方法内部实现退出行为时,使用一个描述性的、易于理解的字符串值是很有帮助的。我们将能够通过
quit_item 的 ID 在选择事件中引用菜单项。现在启动模拟器并按下 Menu 按钮。我认为您会喜欢所看到的情景!
图 8. 好图标!(由 Glyphish
提供)
实现菜单行为
现在我有一个外观漂亮的图标,可以用于 Quit 菜单项(我希望您也有一个图标用于自己的应用程序),但我仍然需要添加代码,从而告诉应用程序当按钮被按下时应该做什么。
实现选项菜单中的任意行为都要从重写 onOptionsItemSelected
方法开始。因此重写该方法,然后更新代码,使其看起来像下面这样(但记住要针对您自己的应用程序调整菜单项 ID):
清单 3. 处理菜单项选择
public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.quit_item: this.finish(); return true; default: return super.onOptionsItemSelected(item); } } |
注意,这只是一条简单的 switch 语句。如果选择 quit_item
的 id,将调用 finish 方法来关闭应用程序。
在模拟器中试用这段新代码:按 Menu 按钮,选择退出(X)选项,并观察
LogCat 上出现的内容。您应该看到一个完整的 Activity 生命周期,依次分为如下几个阶段:onPause、onStop
和 onDestroy。
Android 3.x 中的操作栏
如前所述,较新版本的 Android(Honeycomb 及更高版本)使用操作栏取代了选项菜单。较新的设备甚至不一定有
Menu 按钮,因此了解应用程序的导航(或其他功能)也能用在操作栏中。
确保通过为选项菜单编码而实现的导航功能也能用在操作栏中,并不需要做很多工作。您已经实现了所有需要的方法,剩下的工作只是对
XML 源文件进行一些修改。
首先需要创建一个模拟器实例,用于模拟使用操作栏而非菜单按钮的设备。最简单的做法是模拟一台平板电脑。在
Android SDK 安装中启动 Android SDK Manager 命令行应用程序(是位于 tools
目录中的 android 命令)。SDK Manager 启动并运行后,从 Tools 菜单选择 Manage
AVDs... 选项。这将显示一个对话框,在其中可以定义一个新的模拟器或 Android Virtual
Device(或 AVD)。选择 7.0'' WSVGA (Tablet) (1024 x 600: mdpi),然后将模拟器的目标设定为至少
Android 4.2.2。完成后,您就有了一个不响应菜单按钮的模拟器,如 图 9 中所示。
图 9. 创建一个平板电脑模拟器
接下来,在该平板电脑实例中启动您的应用程序。您应该在右下角看到一条由三个点组成的垂直线。它看起来很棒,对吗?默认情况下,Android
将保留菜单行为,甚至在较新的显示设备中也是这样。通过更新应用程序的 XML 资源,您可以升级操作栏的外观与行为,让它变得更加自然。
从应用程序的 AndroidManifest.xml 文件开始,您将在该文件中更新
SDK 目标:
<uses-sdk android:minSdkVersion="11" android:targetSdkVersion="17" /> |
接下来,在 Eclipse 中进入您项目的 Properties 页面,并将
Project Build Target 更新为高于 Android 4.2.2 的任意 Android
版本。单击 OK 并让项目重新编译。然后在 menu 目录中找到菜单 XML 文件。更新它的内容,如下所示,这将保留
Quit 的 item 定义。
android:showAsAction="always" |
最后,如果您的项目在 res 目录下没有两个名为 values-v11
和 values-v14 的子目录,那么创建它们。接下来,在 values-v11 目录中添加以下 XML
文件:
<resources> <style name="AppBaseTheme" parent="android:Theme.Holo.Light"></style> </resources> |
在 values-v14 目录中,添加此文件:
<resources> <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar"></style> </resources> |
现在重启模拟器,您的新图标应该出现在右上角:
图 10. 一个带图标的操作栏
现在回到 menu 目录中的菜单文件(其中定义了 quit 项),将
showAsAction 更改为 never。重新运行您的应用程序,应该可以在右上角看到这三个垂直的点。
不要忘记重新设定
注意,如果希望将应用程序目标保持为 Gingerbread,您需要重新设定项目的编译目标并撤消本节内容中对
XML 文件所做的更改。这些更改无法做到向后兼容!
图标的更多乐趣
迄今为止,您已经为以 Gingerbread 为目标的应用程序添加了一个菜单选项,看到它被十分完美地转换到实现操作栏的新设备上,并了解如何通过对应用程序的
XML 文件进行一些更新来升级该功能(如果您选择这样做)。
现在,让我们总结一下您学到的关于图标的内容。您已经完成了为应用程序的导航菜单添加一个图标的主要工作,因此更新它的
main 图标应该没什么问题。对用户而言,这个图标就代表着您的应用程序,因此必须知道如何更新和定制它。
我将更新 Overheard Word 的图标,您也可以对自己的应用程序这样做。再说一遍,在
Internet 上进行快速搜索可以找到大量的图标站点。在这些站点中,我发现了一个有趣的图标集合,其中有一个图标确实深受我的喜爱:
图 11. 一个漂亮的新图标
回想一下,这个图标在不同的设备配置文件上呈现不同的效果。我希望确保用户对
Overheard Word 产生良好的第一印象,因此让图标分辨率适合我的目标设备范围是很有必要的。幸运的是,我知道一个真正好用的站点,可以帮我实现这个目标。
投资图标
使用免费图标达到演示目的没有问题,但为了专业应用程序而投资定制图标是绝对有必要的。图标(或图标集)体现了您应用程序的品牌,您希望它是独一无二的。如果它很一般,或者看起来明显很业余,用户会对您的应用程序做出什么结论呢?
Android Asset Studio(参见 参考资料)是一个 Google
Code 项目,拥有大量可为 Android 开发人员提供助力的实用工具。我使用频率很高的一个工具是 Launcher
Icons。我要做的就是单击 Launcher Icons 链接,然后上传我的图标。该实用工具会针对各种设备配置文件生成正确尺寸的图标文件,然后我可以
zip 文件的格式下载它。该文件包含四个目录,每个目录下都包含一个我上传文件的特定分辨率与尺寸的版本。
图 12. Launcher Icons
为 Android 制作尺寸正确的图标
接下来,我将每个目录中的 ic_launcher.png 文件复制到我应用程序的
res 文件夹的相同子目录中。注意,在此过程中,我可能会替换 Eclipse 生成的原始图标文件。
最后,我再次运行应用程序,并等它出现在我的模拟器实例中。我单击 Home
按钮,然后查看结果:一个漂亮的应用程序图标(对我而言)标志着 OverHeard Word 是所有用户设备上最有趣的应用程序!
图 13. 现在变得很形象!
结束语
在本文中,您了解了 Activity 的生命周期,并知道如何使用它来改进应用程序对设备资源的利用。您还学会了如何使用菜单和操作栏定义与实现导航构件,以及如何使用图标替换单词按钮。
您在本文中学到的所有内容对于构建 Android 应用程序都是至关重要的。Android
上的移动开发很容易上手,当然也乐趣无穷,但我希望您也要明白它与您所熟悉的 Java 开发属于不同范式。Google
Play 与其他应用程序商店中存在着成千上万个应用程序,因此通常只有规划良好、设计用心和编码精妙的应用程序才能名列前茅。要学的地方还有很多!
|