Kotlin AndroidプロジェクトでAndroidAnnotationsを使う

AndroidでKotlinが使えるようになったのでかなり楽にプログラミングできるようになりましたが、それでもまだ[AndroidAnnotations](https://github.com/excilys/androidannotations)を使った方が便利なことは多いので、私はほぼ全てのAndroidアプリで使っています。

Kotlinプロジェクトでアノテーションプロセッシングをするためには[kapt](https://kotlinlang.org/docs/reference/kapt.html)を使います。[android-apt](https://bitbucket.org/hvisser/android-apt)プラグインを使ったことがあるならほとんど追加で覚えることはありません。`apt`で設定していた依存ライブラリを`kapt`で設定すれば良いだけです。

以下がKotlin AndroidプロジェクトにAndroidAnnotationsを導入するための設定です。先頭に`apply plugin: 'kotlin-kapt'`を追加するのと、依存ライブラリに`kapt 'org.androidannotations:androidannotations:4.3.1'` と `compile 'org.androidannotations:androidannotations-api:4.3.1'` を追加するだけです。

```groovy
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt' // これを追加

...

dependencies {
    compile 'com.android.support:appcompat-v7:26.+'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"

    // AndroidAnnotations
    kapt 'org.androidannotations:androidannotations:4.3.1'
    compile 'org.androidannotations:androidannotations-api:4.3.1'

    // OrmLite
    // kapt 'org.androidannotations:ormlite:4.3.1'
    // compile 'org.androidannotations:ormlite-api:4.3.1'

    // Rest client
    // kapt 'org.androidannotations:rest-spring:4.3.1'
    // compile 'org.androidannotations:rest-spring-api:4.3.1'
}
```

単純なプロジェクトならこれで動きますが、ビルドフレーバーを設定していたりすると上手く動かないときがあります。そういう場合の対処法は……
現在調査中です。

## 注意

AndroidAnnotationsを使っていたJavaコードをそのままKotlinに変換しただけではうまく動かない箇所がいくつかあります。

### open修飾子を付ける

JavaとKotlinの大きな違いは、**Kotlinのクラス・メソッドは何も指定しないとJavaのfinalクラス・メソッドになる**ということです。つまりKotlinのクラス・メソッドはデフォルトでは継承できません。
AndroidAnnotationsはアノテーションプロセッシングにより継承クラスを生成したりメソッドをオーバーライドしたりしますが、finalクラス・メソッドになっているとオーバーライドできないのでエラーになってしまいます。`@EActivity`や`@EBean`などのクラスに指定するアノテーションは全てサブクラスを生成するので`open`を付けるようにしてください。また、`@UiThread`や`@Background`などのアノテーションをメソッドに付ける時も同様に`open`が必要です。`@Click`や`@AfterViews`などはメソッドそのものをオーバーライドするわけではないので、`open`を付けなくても良いです。

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

    @AfterViews
    fun initView() {
        // View初期化処理
    }

    @UiThread
    open fun func() {
        // メインスレッド処理
    }

    @Click
    fun button() {
        // android:id="@id/button" のクリック処理
    }
}
```

### フィールドアノテーションの付け方

`@ViewById`や`@Bean`などのアノテーションはフィールドに付けますが、Javaでこれらのアノテーションを使ったコードをKotlinに変換しただけでは、エラーになってしまいます。何故かと言うとKotlinのクラス内に宣言する`var`は実際にはフィールドの宣言ではなく、プライベートフィールドとゲッター（とセッター）の宣言に相当するものだからです。フィールドがプライベートになると生成されたサブクラスからの代入ができなくなるため、エラーになります。

このようなアノテーションを使う時は、[lateinit var](https://kotlinlang.org/docs/reference/properties.html)で宣言すると良いです。`lateinit var`はコンストラクタで初期化はされないが、フレームワーク内の初期化フローの中で初期化され、実質的にnon-null型と見て問題ないプロパティを表します。`@ViewById`や`@Bean`などは、まさにこの用途にぴったりです。

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

    @ViewById
    lateinit var list: RecyclerView

}
```

ただし、複数画面対応をする場合に画面の向きに応じてレイアウト内のViewの種類が異なる場合など、`@ViewById`を付けたフィールドに`null`が入る可能性がある場合はこの方法は使えません。こういう時は`@JvmField`を使って`var`でnullable型を宣言します。

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

    @ViewById
    @JvmField
    var text: TextView? = null

}
```