Android 应用程序中的整洁代码
假设有一天早上你醒来,心想:“嘿,我今天要构建一个 Android 应用。”首先,这是一个不错的选择!截至 6 月底,每天有 500,000 台 Android 设备被激活,甚至超过了 iPhone。这意味着您的应用拥有庞大的潜在用户群体。此外,Android 是使用 Java 构建的。这可能看起来并不重要,但我已经在Objective-C 上工作了几年iOS 平台,虽然我现在对此感到非常满意,但iOS SDK 提供的学习曲线比我在 Android 上遇到的要陡峭。当我第一次开始使用Android SDK 时,Android 感觉更容易上手。也就是说,与您过去构建的任何其他 Java 应用程序相比,它确实存在一些明显的差异,我将在第一部分中介绍其中的一些。
因此,随着时间的推移,您已经完成了第一个应用程序,并将其提交到Android Market。您应该得到祝贺,因为您的朋友们都在下载您的应用程序并在 Twitter 上谈论它。现在是时候开始您的第二个应用程序了。您花费了几天时间,突然意识到您开始重用第一个应用程序中的代码,这本身并不是一件坏事。代码重用可能很有价值。但是您注意到有很多样板代码经常重复出现,这可能会分散您对业务逻辑的注意力。幸运的是,有一些方法可以改进这一点。
在这篇博文中,我将概述 Android 和应用程序生命周期,并讨论框架施加的一些限制。我还将回顾一些可以帮助您清理 Android 代码并专注于您希望通过应用程序实现的目标的技术和第三方项目。
Android 概述
让我们从 Android 的工作原理的简要概述开始。Android 应用程序(应用)使用 Java 构建,并编译成类文件。然后将类文件编译成 Dalvik 可执行文件 (DEX) 格式,以便它们可以在 Android 使用的 Dalvik 虚拟机上运行。转换为 DEX 格式后,类文件会被压缩到 Android 包 (APK) 中,以便分发到设备上。由于使用了 DEX 格式,因此 Dalvik VM 不是真正的 Java 虚拟机,因为它不处理 Java 字节码。此外,Dalvik VM 基于 Apache Harmony 项目的一个子集,作为其核心类库。这意味着您习惯使用的许多 Java SE 类和方法都可用,但肯定不是全部。我发现API 参考 在Android 开发者网站上是一个宝贵的资源,可以用来回顾这些差异。
默认情况下,每个 Android 应用程序都会由 Android 操作系统分配一个唯一的 Linux 用户 ID。当系统启动应用程序时,它会在其自己的 Linux 进程中,在其自己的虚拟机 (VM) 内运行。系统根据需要管理此进程的启动和关闭。正如您所料,这意味着每个应用程序都与其他正在运行的应用程序隔离运行。安装后,应用程序可以请求访问硬件功能或与其他应用程序交互的权限。用户可以选择授予应用程序这些权限或不安装它。应用程序需要或请求的权限在每个应用程序的 Android 清单文件中定义。这是一个 XML 文件,列出了应用程序的所有组件,以及这些组件的任何设置。四种类型的应用程序组件是活动、服务、内容提供程序 和广播接收器。出于本文的目的,我将重点关注活动。
活动基本上代表 Android 应用程序的单个屏幕。例如,一个 Twitter 应用程序可能有一个登录屏幕、一个包含推文列表的屏幕和一个用于撰写新推文的屏幕。这些屏幕中的每一个都代表应用程序中的不同活动。作为开发人员,您永远不会自己实例化活动对象。通过发送称为Intent 的异步消息来激活活动,如下面的示例所示。
startActivity(new Intent(context, HomeActivity.class));
当调用startActivity(Intent intent) 时,系统会创建一个新实例或重用现有实例,以便向用户显示活动。重要的是,系统控制应用程序和每个活动的启动和停止以及创建和销毁。如果您想与此过程交互,那么应用程序和活动类提供了用于不同生命周期事件 的方法,您可以在子类中覆盖这些方法。
依赖注入
Spring Android 项目最近发布了其第四个里程碑 版本。在该版本中,我们继续改进RestTemplate 和Spring Social 对 Android 的支持,这简化了进行 RESTful HTTP 请求和访问受OAuth 保护的 REST API 的过程。虽然我们认为这些是 Android 开发的宝贵补充,但一些开发人员询问了 Spring Android 中是否可能支持依赖注入,因为您可能知道,Spring Framework 已经提供了一个流行的控制反转 (IOC) 容器,用于在企业 Java 应用程序中启用依赖注入。在 Spring Android 的早期规划阶段,依赖注入支持被确定为该项目中可能包含的候选功能。在那时,尚不清楚该支持将包含什么内容以及如何实现。因此,我开始研究和调查在 Android 中执行依赖注入的可用方法和限制。
那么,什么是依赖注入?如果您问两个不同的开发人员,您可能会得到两个不同的答案。您可能会听到有关 IOC、XML 文件、注释或其他一些实现细节的信息。实际上,依赖注入只是一种通过向对象提供其工作所需内容来减少耦合的技术,而不是让对象扩展到其环境中。这听起来很容易,您可能在想自己已经可以通过类构造函数和 setter 方法实现这一点,这完全正确。但是,请回想一下上面概述部分中提到的内容,Android 系统驱动应用程序生命周期,因此我们可以执行此操作的方式是有限的。
Android 方式
无需使用任何第三方库,将依赖项传递给 Activity 就非常容易。如前所述,系统创建应用程序实例。因此,通过扩展应用程序,您可以有效地创建一个单例依赖项实例,然后任何应用程序中的活动都可以访问该实例。
public class MainApplication extends Application {
private MyService service;
@Override
public void onCreate() {
super.onCreate();
service = new MyServiceImpl();
}
public MyService getMyService() {
return this.service;
}
}
活动类有一个名为getApplication() 的方法,该方法返回对拥有该活动的应用程序对象的引用。我们只需将其强制转换为 MainApplication,就可以访问 MyService 的 getter 方法。当然,活动现在必须“了解”应用程序,这似乎是一个缺点。但请记住,活动已经了解其应用程序。该方法是内置的。
public class MainActivity extends Activity {
private MyService service;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MainApplication app = (MainApplication…