【译】使用 Dart & Henson 改进 Android Intents

 

一种更好的使用AndroidIntents的方式,解决之前的种种痛点,作者来自团购鼻祖Groupon公司,值得大家一看。...



原文:Better Android Intents with Dart & Henson

作者:Daniel Molinero Reguera
译者:汤涛

最近在忙一些事情,很久没发文了,最近看到这篇文章,感觉不错,就翻译了一下,推荐给大家。文中提到的 Android Intent 的种种问题,有些也是我之前遇到的一些痛点,项目规模稍大一些后,有些问题会慢慢暴露出来,虽不是非常严重,但正是对代码的精益求精,才是我们不断进步的源泉,也是我推荐文章的重要标准。作者来自著名的团购鼻祖 Groupon 公司,相信这篇分享值得大家一看。

因微信限制,正文中外链不可点击,大家可以点击文末阅读原文,访问我简书原文查看。



Intent 是 Android 生态系统的重要组成部分。他们用来表达一个执行动作,可分为隐式和显式 Intent。在应用程序内部,所有的 Intent 以一种抽象的方式,一起定义了一个信息传递层。在本文中,我们将解释为什么 Android 创建显式 Intent 的方式容易出错,也给大家展示一些有问题的应对方案。最后,我们将介绍一个生成这种信息传递层的库:Dart & Henson,它使用简单,能方便、快捷与健壮地在你的 Activity 和 Service 之间传递信息。

显示 Intent 需要明确指定组件,常用于在应用内的 Activity 或 Intent 之间传递信息,额外的信息通过extras 提供给目标组件,与 Intent 一起传递。比如下面的代码,创建了一个显示 Intent 来启动 Activity:



被启动的 Activity 代码可能是这样的:



这种机制很好地处理了组件的创建与通信,但仍然有一些问题需要注意:

  • 目标组件作为一个实体,对输入没有任何控制权。在我们的例子里,itemId 是必需的,但如果没有传递它,DetailActivity 最好的处理方式也只能是抛出异常。
  • Intent 的创建(完全)不够健壮,并没有对 extra 中的 key 或 value 做任何检查。
一分预防胜过十分治疗

有问题的解决方案

解决这些问题的一个可能的方案是Intent 工厂模式。它主要由一些工厂方法组成,包含了应用程序里用到的各种 Intent。比如像下面这样的 Intent 工厂:



然而,这种解决方案有一些局限,并不是一个很好的办法。

  • Intent 工厂是一个集中类,这个类可能会变得很大且复杂。
  • 它违背了开放/闭合原则。对修改并没有关闭,我们将总是需要给每个新的 Activity 添加一个新方法。
  • 目标组件应该是唯一知晓参数细节与逻辑的地方。
  • 可选参数处理。同一个组件有不同的需求,是否应该写不同的方法?还是写一个方法并使用默认值?
  • 它会诱使后续的开发人员模仿,进而产生其他的 Intent 工厂,最终演变成大泥球模式,使得代码越来越糟。
有一个类似的策略可以分散这些工厂方法到各自的目标组件。也就是指,每个组件可以包含一个(或多个)静态方法,用于生成这些启动它自身的 Intent。这个办法可以解决开放/闭合原则的问题,分解 Intent 工厂,也许还可以避免大泥球模式。尽管如此,关于可选参数的问题依然存在。有人说builder 模式可以?我们自己实现它?…

我选择用懒惰的人做困难的工作,因为一个懒惰的人会找到简单的方法完成它。比尔盖茨

Dart 2 & Henson

Dart 是一个 Android 开源库。它绑定 Activity 字段到 Intent extra,Butter Knife 也是用类似的方案,关联 Activity 与 XML 布局中的View。在我们的例子里,它看起来是这样:



@InjectExtra 注解声明了一个同名的 extra key,默认情况下,所有的注解字段都是必需的,如果 extra 没有提供,会抛出异常。如果想使其可选,需要加上 @Nullable 注解。接下来,只需要调用Dart.inject 即可自动生成相关代码。

在  Groupon,我们意识到注解里的那些信息,已经足够创建我们一直想要的builder模式。因此,我们决定在 Dart 基础上再进一步:我们做了一个注解处理器,用于生成Intent builders,这个新模块叫做  Henson,它集成在 Dart 2 中。

DetailActivity 这个例子里,Henson 生成了一个小型的领域特定语言 (DSL),来使得跳转到 DetailActivity 变得非常容易:



首先是通过Henson.with(context).gotoXXX() 获取目标 Activity 或 Service 的 builder。然后,使用自动生成的方法设置必需的 extras,  比如 itemId 是使用 itemId(String str)。之后,用同样的方式设置可选参数。最后调用build,你就可以得到一个有效的 Intent,用于启动你的组件。

这段领域特定语言(DSL)会为所有@InjectExtra 注解标记的字段生成相关类。这相当于一个信息传递层,解决了我们创建 Intent 时碰到的那些问题:

  • 通过注解,目标组件对extras 拥有完全的控制权
  • DSL 定义在组件内的一处,如果它有修改,产生的问题都可以在编译时被发现。
  • 没有违反开放/闭合原则,实际上,我们什么都不需要写,一切都是自动生成
  • 因为使用了builder 模式,可选参数很容易实现。
  • 还可以自动补全代码!
完整的示例代码在这里。

https://github.com/f2prateek/dart/tree/master/dart-sample

总结

Henson 创建了一个小型的领域特定语言(DSL),可以更加健壮地构建启动 Activity 与 Service 的 Intent,它允许缺失必需的extra,支持灵活的可选参数,最棒的是,使用 Dart 2 与 Henson,你一行代码也不必写了。


    关注 Android程序员


微信扫一扫关注公众号

0 个评论

要回复文章请先登录注册