Android (Kotlin) のコード簡略化ツールを調べてみた

この種のツールは何と呼ぶのが正しいのかわかりませんが、アノテーションを使って定型コードを簡略化できるツールについて調べてみました。

AndroidAnnotations v4.3.1

まずは、この種のツールの(多分)走りである AndroidAnnotations です。

機能は、Activity に対するレイアウトの指定から、スレッドや REST クライアントなど、多岐に渡ります。

Ref. AvailableAnnotations · androidannotations/androidannotations Wiki

若干癖があるのが、ビルド時にサブクラスを生成するところです。

例えば、MyActivity@EActivity を付けた場合、MyActivity_ というサブクラスができるので、マニフェストファイルでは、MyActivity_ の方で記述する必要があります。

Kotlin で使う時の注意点は、以下の記事が参考になります:

AndroidAnnotations with Kotlin - Qiita

まず、Java と同様に書いてみます:

@EActivity(R.layout.activity_main)
open class MainActivity : AppCompatActivity() {

    @ViewById(R.id.name)
    var name: TextView? = null

    override open fun onCreate(savedInstanceState: Bundle?) {
        name?.setText("something")
.....

ビルドすると、org.androidannotations.annotations.ViewById cannot be used on a private element というエラーになってしまいます。

(エラーは app/build/generated/source/kapt/androidannotations.log に出力されます。)

android - AndroidAnnotations - ViewById cannot be used on a private element - Stack Overflow」によると、lateinit を使え、となっているので、書き換えてみます:

@ViewById(R.id.name)
lateinit var name: TextView

そうするとビルドは通りますが、実行時に kotlin.UninitializedPropertyAccessException: lateinit property toolbar has not been initialized というエラーになってしまいます。

このエラーは結局解消できませんでした。

Butter Knife v8.8.1

次に Butter Knife です。

Butter Knife は、AndroidAnnotations に比べると、機能が絞り込まれていて、できるのは、ビュー、リソース、リスナーのバインディングぐらいです。

AndroidAnnotations のようにマニフェストファイルでの指定が変わることはないので、手軽に使えます。

まずは、AndroidAnnotations と同様に、nullable で定義してみます:

@BindView(R.id.name)
var name: TextView? = null
.....
name?.setText("something")

これはうまく動作しました。

ちなみに、lateinit を使うと、AndroidAnnotations と同様の実行時エラーが出ます。

以下の issue でも解決策がありません:

kotlin.UninitializedPropertyAccessException when I use Kotlin with ButterKnife · Issue #38 · JetBrains/kotlin-examples

Kotter Knife v0.1.0

Kotter Knife は Butter Knife の Kotlin 版です。

Kotter Knife を使うと、シンプルに書けるようになります:

val name: TextView by bindView(R.id.name)

ちなみに by は、Kotlin の Delegated Properties という機能です。

Kotlin Android Extensions

Kotlin Android Extensions は、findViewById を省略できるようにするもので、Android Studio の Kotlin プラグインに含まれています。

これを使うと、コードは以下のようになります:

// Using R.layout.activity_main from the main source set
import kotlinx.android.synthetic.main.activity_main.*

class MyActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        textView.setText("Hello, world!")
        // Instead of findViewById(R.id.textView) as TextView
    }
}

(引用元:Kotlin Android Extensions - Kotlin Programming Language

アノテーションも不要なので、非常にシンプルですね。

ただし、import の部分がどうしても解決できず、動きませんでした。

その他

DIフレームワークでも同様のことができるようですが、今回は調べていません。

まとめ

結局、動いたのは Butter Knife と Kotter Knife だけでした。

Kotlin で使う場合は Kotter Knife の方が良さそうですね。