從 Butter Knife 到 Kotter Knife 再到 Kotlin Android Extensions

Butter Knife

Butter Knife 是安卓開發(fā)中常用的一種 View 綁定框架,主要用來減少 View 的獲取&強轉(zhuǎn)的樣板代碼。

原生的安卓 Java 代碼中,控件需要自己手動獲取和強制轉(zhuǎn)換盟步。

ListView simpleListView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    // ...
    View view = findViewById(R.id.simple_list);
    simpleListView = (ListView) view;
    simpleListView.setAdapter(adapter);
}

如上面代碼所示,至少要經(jīng)歷三個步驟:

  1. 聲明 View 變量躏结,包含 View 的具體類型(simpleListView 對象却盘,ListView 類型)
  2. 調(diào)用 findViewById 方法獲取資源的 View 對象
  3. 將 View 對象強制轉(zhuǎn)換成對應(yīng)類型的 VIew(ListView)

雖然 2-3 步可以簡化成一行代碼,但是經(jīng)歷的步驟一定是分明的媳拴。

但是通過 View 綁定黄橘,這個步驟可以簡化到一步:


@BindView(R.id.simple_list) ListView simpleListView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    // ...
    simpleListView.setAdapter(adapter);
}

沒有 simpleListView 的賦值過程,當(dāng)然更不會有類型轉(zhuǎn)換代碼屈溉。因為這之間的步驟 Butter Knife 框架幫你做了塞关。你只用告訴它資源 ID 和接收對象即可,也就是 BindView 注解的作用子巾。

Kotlin 是怎么做的

var simpleListView: ListView? = null
simpleListView = findViewById(R.id.simple_list) as ListView
simpleListView?.adapter = adapter

在 Kotlin 中也逃不過這三個步驟帆赢,但是相比 Java 的優(yōu)點是強制轉(zhuǎn)換只需要 as 關(guān)鍵字,手敲幾乎沒不方便的地方线梗。用 Java 的情況下椰于,大家?guī)缀醵际窃诘忍栍疫呏苯诱{(diào)用 findViewById 然后按 <Ctrl + Enter> 快捷鍵讓 IDE 自動糾正代碼這種方式。仪搔。瘾婿。

所以面對這種問題,即便是語法靈活得多的 Kotlin 也沒有太大優(yōu)勢,類型的強制轉(zhuǎn)換總是非常令人厭惡的憋他。而且 Kotlin 原生并不支持 Butter Knife 孩饼。

讓 Kotlin 也用上 View 綁定

讓 Kotlin 用上方便的 View 綁定功能主要是兩種方式,它們都挺簡單:

  1. 讓 Butter Knife 在 Kotlin 上正常工作
  2. 選擇原生 Kotlin 所支持的 View 綁定框架

第一種方式:

@BindView(R.id.simple_list) @JvmField var simpleListView: ListView? = null

JvmField 注解讓 Kotlin 實例的字段具有與底層相同的可見性竹挡,即對 Java 是可見的镀娶,當(dāng)然它的前提必須是非私有屬性。這點對于需要屬性注入的情況是必須的揪罕,同時也是 Kotter Knife 原生不能支持 Kotlin 的原因梯码。

例如 Kotlin 中并沒有 “靜態(tài)變量” 這個元素,但是提供了 companion object 來模擬靜態(tài)的調(diào)用方式好啰。但是 companion object 在底層仍然不是靜態(tài)的轩娶,這對于 Java 而言企圖通過靜態(tài)調(diào)用 Kotlin 的 companion object 里邊的內(nèi)容是不行的。
想讓 Kotlin 在底層產(chǎn)生靜態(tài)實例框往,需要這樣做:

class Key(val value: Int) {
    companion object {
        @JvmField
        val COMPARATOR: Comparator<Key> = compareBy<Key> { it.value }
    }
}

此時的 Key.COMPARATOR 對于 Java(或者其它 JVM 語言)都是是靜態(tài)的鳄抒,它們在底層采樣同樣的方式儲存。第一種方式之所以能解決也是類似的道理椰弊。

第二種方式:

Kotter Knife 是為 Kotlin 語言所寫的 View 綁定框架许溅,它這樣來使用:

val impleListView: ListView by bindView(R.id.simple_list)

從形式上來看,就是把給屬性加注解換成了對屬性訪問進行委托秉版,委托給 bind* 函數(shù)贤重。如果你不了解什么是委托,請看這里清焕。
注意:Kotlin 中的 by 關(guān)鍵字只是省略了委托中的樣板代碼并蝗,和委托設(shè)計模式的思想是一模一樣的。此處的屬性委托背后的實現(xiàn)也非常簡單秸妥,屬性會被延遲計算滚停,第一次訪問時進行 View 的查找和轉(zhuǎn)換,如果沒有找到則會拋出異常粥惧,異常實例是:

IllegalStateException("View ID $id for '${desc.name}' not found.")

究竟應(yīng)不應(yīng)該因為一個注解問題放棄 Butter Knife键畴?
首先你要明白,畢竟 @JvmField 也是 Kotlin 語言重要部分的元素之一影晓,這個重要的部分就是:和 Java 的交互調(diào)用。所以 Kotlin 并不算是不支持 Butter Knife檩禾,在需要它的時候不用多慮挂签,毫無疑問可以當(dāng)做完全兼容的 Java 類庫使用。

Kotlin Android Extensions

然而說到這里盼产,本文的主角還未介紹過... 因為介紹它的時候就是拋棄上述所有東西的時候饵婆。你可以將它當(dāng)做 Kotlin 官方對安卓開發(fā)提供的加強支持:它包括了 View 綁定,并且是一種更方便的新形式戏售。它就是: Kotlin Android Extensions

給項目模塊的 build.gradle 添加配置:

apply plugin: 'kotlin-android-extensions'

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"
    }
}

然后侨核,就可以直接使用生成的對象了:

// 不可少的 import
import kotlinx.android.synthetic.main.fragment_main.*
// 省略其它 import
class MyFragment : Fragment {
    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // 直接使用 ListView 對象
        simple_list.adapter = adapter
    }
    // ...
}

注意:我沒有聲明任何的 ListView 對象草穆,更沒有相應(yīng)的賦值操作,simple_list 是資源 ID搓译。也就是說:我直接將資源 ID 名 simple_list 當(dāng)做該 ListView 的對象實例使用悲柱。

當(dāng)然,上面的 import 是不能少的些己,import 的規(guī)則是:

import kotlinx.android.synthetic.main.<layout>.*

即 import 了相應(yīng)的 layout 豌鸡,就能直接使用里邊具有 id 屬性的 View 實例,將 1-2-3 個步驟全部省略段标,可謂是最方便的形式涯冠。

最后

雖然 Butter Knife 非常優(yōu)秀,但是既然我能更優(yōu)雅的解決問題逼庞,還能減少依賴蛇更,何樂不為。所以:既然你用上了 Kotlin赛糟,那么請丟棄所有的 View 注入框架派任。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市虑灰,隨后出現(xiàn)的幾起案子吨瞎,更是在濱河造成了極大的恐慌,老刑警劉巖穆咐,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件颤诀,死亡現(xiàn)場離奇詭異,居然都是意外死亡对湃,警方通過查閱死者的電腦和手機崖叫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拍柒,“玉大人心傀,你說我怎么就攤上這事〔鹧叮” “怎么了脂男?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長种呐。 經(jīng)常有香客問我宰翅,道長,這世上最難降的妖魔是什么爽室? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任汁讼,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘嘿架。我一直安慰自己瓶珊,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布耸彪。 她就那樣靜靜地躺著伞芹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪搜囱。 梳的紋絲不亂的頭發(fā)上丑瞧,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機與錄音蜀肘,去河邊找鬼绊汹。 笑死,一個胖子當(dāng)著我的面吹牛扮宠,可吹牛的內(nèi)容都是我干的西乖。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼坛增,長吁一口氣:“原來是場噩夢啊……” “哼获雕!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起收捣,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤届案,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后罢艾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體楣颠,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年咐蚯,在試婚紗的時候發(fā)現(xiàn)自己被綠了童漩。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡春锋,死狀恐怖矫膨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情期奔,我是刑警寧澤侧馅,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站呐萌,受9級特大地震影響馁痴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜搁胆,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一弥搞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧渠旁,春花似錦攀例、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至杂靶,卻和暖如春梆惯,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背吗垮。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工垛吗, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人烁登。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓怯屉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親饵沧。 傳聞我的和親對象是個殘疾皇子锨络,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345

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