【譯】使用 Dart & Henson 改進(jìn) Android Intents

聲明:本文也在我的微信公眾號(hào) Android程序員(AndroidTrending) 發(fā)布别凤。

原文鏈接:Better Android Intents with Dart & Henson
原文作者:Daniel Molinero Reguera
譯文出自:湯濤的簡書
譯者:湯濤
狀態(tài):完成

最近看到這篇文章,感覺不錯(cuò),就翻譯了一下低剔。文中提到的 Android Intent 的種種問題,有些也是我之前遇到的一些痛點(diǎn)向臀,項(xiàng)目規(guī)模稍大一些后工三,有些問題會(huì)慢慢暴露出來,雖不是非常嚴(yán)重讲冠,但正是對(duì)代碼的精益求精瓜客,才是我們不斷進(jìn)步的源泉,也是我推薦文章的重要標(biāo)準(zhǔn)竿开。作者來自著名的團(tuán)購鼻祖Groupon公司谱仪,相信這篇分享值得大家一看。

Buster Keaton?—?The Battling Butler.jpg

Intent 是 Android 生態(tài)系統(tǒng)的重要組成部分否彩。他們用來表達(dá)一個(gè)執(zhí)行動(dòng)作疯攒,可分為隱式和顯式 Intent。在應(yīng)用程序內(nèi)部列荔,所有的 Intent 以一種抽象的方式敬尺,一起定義了一個(gè)信息傳遞層。在本文中贴浙,我們將解釋為什么 Android 創(chuàng)建顯式 Intent 的方式容易出錯(cuò)砂吞,也給大家展示一些有問題的應(yīng)對(duì)方案。最后崎溃,我們將介紹一個(gè)生成這種信息傳遞層的庫:Dart & Henson蜻直,它使用簡單,能方便、快捷與健壯地在你的 Activity 和 Service 之間傳遞信息袭蝗。

顯示 Intent 需要明確指定組件唤殴,常用于在應(yīng)用內(nèi)的 Activity 或 Intent 之間傳遞信息,額外的信息通過 extras 提供給目標(biāo)組件到腥,與 Intent 一起傳遞朵逝。比如下面的代碼,創(chuàng)建了一個(gè)顯示 Intent 來啟動(dòng) Activity:

Intent intent = new Intent(context, DetailActivity.class);
intent.putExtra(EXTRA_ITEM_ID, selectedItem.id);
intent.putExtra(EXTRA_SHOW_MAP, true);
startActivity(intent);

被啟動(dòng)的 Activity 代碼可能是這樣的:

public class DetailActivity extends Activity {
  public static final String EXTRA_ITEM_ID = "extra.item_id";
  public static final String EXTRA_SHOW_MAP = "extra.show_map";

  private String itemId;
  private boolean shouldShowMap;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    itemId = getIntent().getStringExtra(EXTRA_ITEM_ID);
    shouldShowMap = getIntent().getBooleanExtra(EXTRA_SHOW_MAP, false);

    if (itemId == null) {
      throw new IllegalArgumentException("Item Id is required");
    }
    ...
  }
  ...
}

這種機(jī)制很好地處理了組件的創(chuàng)建與通信乡范,但仍然有一些問題需要注意:

  • 目標(biāo)組件作為一個(gè)實(shí)體配名,對(duì)輸入沒有任何控制權(quán)。在我們的例子里晋辆,itemId 是必需的渠脉,但如果沒有傳遞它,DetailActivity 最好的處理方式也只能是拋出異常瓶佳。
  • Intent 的創(chuàng)建(完全)不夠健壯芋膘,并沒有對(duì) extra 中的 key 或 value 做任何檢查。

一分預(yù)防勝過十分治療

有問題的解決方案

解決這些問題的一個(gè)可能的方案是 Intent 工廠模式霸饲。它主要由一些工廠方法組成为朋,包含了應(yīng)用程序里用到的各種 Intent。比如像下面這樣的 Intent 工廠:

public class IntentFactory {
  public Intent newDetailActivityIntent(Context context, String itemId, boolean showMap) {
    Intent intent = new Intent(context, DetailActivity.class);
    intent.putExtra(EXTRA_ITEM_ID, itemId);
    intent.putExtra(EXTRA_SHOW_MAP, showMap);
    return intent;
  }
  ...
}

然而厚脉,這種解決方案有一些局限习寸,并不是一個(gè)很好的辦法。

  • Intent 工廠是一個(gè)集中類傻工,這個(gè)類可能會(huì)變得很大且復(fù)雜霞溪。
  • 它違背了開放/閉合原則。對(duì)修改并沒有關(guān)閉中捆,我們將總是需要給每個(gè)新的 Activity 添加一個(gè)新方法鸯匹。
  • 目標(biāo)組件應(yīng)該是唯一知曉參數(shù)細(xì)節(jié)與邏輯的地方。
  • 可選參數(shù)處理泄伪。同一個(gè)組件有不同的需求殴蓬,是否應(yīng)該寫不同的方法?還是寫一個(gè)方法并使用默認(rèn)值臂容?
  • 它會(huì)誘使后續(xù)的開發(fā)人員模仿,進(jìn)而產(chǎn)生其他的 Intent 工廠根蟹,最終演變成大泥球模式脓杉,使得代碼越來越糟。

有一個(gè)類似的策略可以分散這些工廠方法到各自的目標(biāo)組件简逮。也就是指球散,每個(gè)組件可以包含一個(gè)(或多個(gè))靜態(tài)方法,用于生成這些啟動(dòng)它自身的 Intent散庶。這個(gè)辦法可以解決開放/閉合原則的問題蕉堰,分解 Intent 工廠凌净,也許還可以避免大泥球模式。盡管如此屋讶,關(guān)于可選參數(shù)的問題依然存在冰寻。有人說 builder 模式可以?我們自己實(shí)現(xiàn)它皿渗?...

我選擇用懶惰的人做困難的工作斩芭,因?yàn)橐粋€(gè)懶惰的人會(huì)找到簡單的方法完成它。比爾蓋茨

Dart 2 & Henson

Dart 是一個(gè) Android 開源庫乐疆。它綁定 Activity 字段到 Intent extra划乖,Butter Knife 也是用類似的方案,關(guān)聯(lián) Activity 與 XML 布局中的View挤土。在我們的例子里琴庵,它看起來是這樣:


public class DetailActivity extends Activity {
  @InjectExtra String itemId;
  @Nullable @InjectExtra boolean shouldShowMap;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Dart.inject(this);
    ...
  }
  ...
}

@InjectExtra 注解聲明了一個(gè)同名的 extra key,默認(rèn)情況下仰美,所有的注解字段都是必需的迷殿,如果 extra 沒有提供,會(huì)拋出異常筒占。如果想使其可選贪庙,需要加上 @Nullable 注解。接下來翰苫,只需要調(diào)用 Dart.inject 即可自動(dòng)生成相關(guān)代碼止邮。

Groupon,我們意識(shí)到注解里的那些信息奏窑,已經(jīng)足夠創(chuàng)建我們一直想要的builder模式导披。因此,我們決定在 Dart 基礎(chǔ)上再進(jìn)一步:我們做了一個(gè)注解處理器埃唯,用于生成 Intent builders撩匕,這個(gè)新模塊叫做 Henson,它集成在 Dart 2 中墨叛。

DetailActivity 這個(gè)例子里止毕,Henson 生成了一個(gè)小型的領(lǐng)域特定語言 (DSL),來使得跳轉(zhuǎn)到 DetailActivity 變得非常容易:

Intent intent = Henson.with(context)
    .gotoDetailActivity()
    .itemId(selectedItem.id)
    .shouldShowMap(true)
    .build();

startActivity(intent);

首先是通過 Henson.with(context).gotoXXX() 獲取目標(biāo) Activity 或 Service 的 builder漠趁。然后扁凛,使用自動(dòng)生成的方法設(shè)置必需的 extras, 比如 itemId 是使用 itemId(String str)。之后闯传,用同樣的方式設(shè)置可選參數(shù)谨朝。最后調(diào)用 build,你就可以得到一個(gè)有效的 Intent,用于啟動(dòng)你的組件字币。

這段領(lǐng)域特定語言(DSL)會(huì)為所有@InjectExtra 注解標(biāo)記的字段生成相關(guān)類则披。這相當(dāng)于一個(gè)信息傳遞層,解決了我們創(chuàng)建 Intent 時(shí)碰到的那些問題:

  • 通過注解洗出,目標(biāo)組件對(duì) extras 擁有完全的控制權(quán)士复。
  • DSL 定義在組件內(nèi)的一處,如果它有修改共苛,產(chǎn)生的問題都可以在編譯時(shí)被發(fā)現(xiàn)判没。
  • 沒有違反開放/閉合原則,實(shí)際上隅茎,我們什么都不需要寫澄峰,一切都是自動(dòng)生成
  • 因?yàn)槭褂昧?builder 模式辟犀,可選參數(shù)很容易實(shí)現(xiàn)俏竞。
  • 還可以自動(dòng)補(bǔ)全代碼!

完整的示例代碼在這里堂竟。

總結(jié)

Henson 創(chuàng)建了一個(gè)小型的領(lǐng)域特定語言(DSL)魂毁,可以更加健壯地構(gòu)建啟動(dòng) Activity 與 Service 的 Intent,它允許缺失必需的extra出嘹,支持靈活的可選參數(shù)席楚,最棒的是,使用 Dart 2 與 Henson税稼,你一行代碼也不必寫了烦秩。??

還不趕緊試試?
f2prateek/dart---Extras "injection" Library for Android

Groupon 正在尋找優(yōu)秀的移動(dòng)開發(fā)工程師郎仆,加入我們只祠,一起構(gòu)建像這樣的優(yōu)秀項(xiàng)目吧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末扰肌,一起剝皮案震驚了整個(gè)濱河市抛寝,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌曙旭,老刑警劉巖盗舰,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異桂躏,居然都是意外死亡钻趋,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門沼头,熙熙樓的掌柜王于貴愁眉苦臉地迎上來爷绘,“玉大人,你說我怎么就攤上這事进倍⊥林粒” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵猾昆,是天一觀的道長陶因。 經(jīng)常有香客問我,道長垂蜗,這世上最難降的妖魔是什么楷扬? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮贴见,結(jié)果婚禮上烘苹,老公的妹妹穿的比我還像新娘。我一直安慰自己片部,他們只是感情好镣衡,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著档悠,像睡著了一般廊鸥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上辖所,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天惰说,我揣著相機(jī)與錄音,去河邊找鬼缘回。 笑死吆视,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的切诀。 我是一名探鬼主播揩环,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼幅虑!你這毒婦竟也來了丰滑?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤倒庵,失蹤者是張志新(化名)和其女友劉穎褒墨,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體擎宝,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡郁妈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了绍申。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片噩咪。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡顾彰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出胃碾,到底是詐尸還是另有隱情涨享,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布仆百,位于F島的核電站厕隧,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏俄周。R本人自食惡果不足惜吁讨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望峦朗。 院中可真熱鬧建丧,春花似錦、人聲如沸波势。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽艰亮。三九已至闭翩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間迄埃,已是汗流浹背疗韵。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留侄非,地道東北人蕉汪。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像逞怨,于是被迫代替她去往敵國和親者疤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,499評(píng)論 25 707
  • 一叠赦、顯式Intent和隱式Intent 參考Android理解:顯式和隱式IntentAndroid中Intent...
    合肥黑閱讀 764評(píng)論 0 1
  • 先看效果圖哈 在.h文件中 在.m文件中 簡單使用 控制器查看圖片https://gitee.com/lanyin...
    凡塵一笑閱讀 1,179評(píng)論 0 2
  • 愛 莫文蔚 流年 王菲 ........
    Zoe_Duan閱讀 262評(píng)論 0 0
  • 思維導(dǎo)圖如果要拍的清晰除秀,僅僅靠手機(jī)相機(jī)有時(shí)候依然不夠糯累。比如,因?yàn)楣饩€問題册踩,會(huì)有陰影泳姐,影響導(dǎo)圖對(duì)外呈現(xiàn)。 掃描全能王...
    童楚涵閱讀 2,083評(píng)論 0 0