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