LoginSignup
21
22

More than 3 years have passed since last update.

Kotlin で Android アプリを書いたときの思い出

Last updated at Posted at 2016-01-19

Kotlin で Android アプリを 1 本書いてみた感想を見て、そういえば自分も(2015-16)年末年始に kotlin を使ってアプリを作ったことを思い出したので感想を書いてみます。

結論(個人の感想です

ActivityやFragment,Service なんかは AndroidAnnotations を利用したほうがスッと書けてました。なので、

  • UIとかのコンポーネント: Java(+AndroidAnnotations)
  • モデル的なところやテストコード: Kotlin

と言った使い分けを行いました。

作ったアプリ

適当に API 叩けたら良かったので、tiqav の API を叩いて、 RecyclerView で画像を表示するアプリを作りました。

numa08/TiquaApp

依存関係

def retrofitVersion = "2.0.0-beta2"
def realmVersion = "0.87.0"

def powerMockVersion = '1.6.4'
def AAVersion = '3.3.2'
def supportVersion = '23.1.1'
def daggerVersion = '2.0'

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile "com.squareup.retrofit:retrofit:$retrofitVersion"
    compile "com.squareup.retrofit:converter-gson:$retrofitVersion"
    compile "com.squareup.retrofit:retrofit-mock:$retrofitVersion"
    compile "com.squareup.retrofit:adapter-rxjava:$retrofitVersion"
    compile "com.squareup.retrofit:adapter-rxjava-mock:$retrofitVersion"
    compile "org.jetbrains.kotlin:kotlin-stdlib:$rootProject.ext.kotlin_version"
    compile "org.jetbrains.kotlin:kotlin-reflect:$rootProject.ext.kotlin_version"
    compile 'org.jetbrains.anko:anko-sdk15:0.7.2'
    compile 'io.reactivex:rxandroid:1.1.0'
    compile 'io.reactivex:rxjava:1.1.0'
    compile 'org.jetbrains.anko:anko-sdk15:0.7.2'
    compile "io.realm:realm-android-library:${realmVersion}@aar"
    compile "io.realm:realm-annotations:${realmVersion}"
    kapt "io.realm:realm-annotations:${realmVersion}"
    kapt "io.realm:realm-annotations-processor:${realmVersion}"
    testCompile "org.robolectric:robolectric:3.0"
    testCompile 'org.apache.commons:commons-lang3:3.4'

    compile "com.android.support:appcompat-v7:${supportVersion}"
    compile "com.android.support:recyclerview-v7:${supportVersion}"
    compile "com.android.support:cardview-v7:${supportVersion}"
    compile "org.jetbrains.kotlin:kotlin-stdlib:$rootProject.ext.kotlin_version"
    testCompile 'org.robolectric:robolectric:3.0'
    testCompile "org.powermock:powermock-module-junit4:${powerMockVersion}"
    testCompile "org.powermock:powermock-module-junit4-rule:${powerMockVersion}"
    testCompile("org.powermock:powermock-api-mockito:${powerMockVersion}") {
        exclude module: 'mockito-all'
    }
    testCompile 'org.mockito:mockito-core:1.10.19'
    testCompile "org.powermock:powermock-classloading-xstream:${powerMockVersion}"
    apt "org.androidannotations:androidannotations:$AAVersion"
    compile "org.androidannotations:androidannotations-api:$AAVersion"
    compile "com.google.dagger:dagger:$daggerVersion"
    apt "com.google.dagger:dagger-compiler:$daggerVersion"
    provided "javax.annotation:javax.annotation-api:1.2"
    compile 'com.squareup.picasso:picasso:2.5.2'
}

実はプロジェクトを

  • API を叩くライブラリ(Kotlin): tiqa4k
  • ライブラリのテスト: tiqa4k-test
  • アプリ本体: app

と3つのモジュールに分けています。

ざっくりと依存ライブラリを紹介します。

全体的な

AndroidAnnotations を利用しました。確かに、View をコントローラーから Data Binding でも良いのですが、Android Annotations には、 Activity や Service, Fragment などの生成、呼び出し、パラメータの指定を簡単に行う仕組みがあります。

@EIntentService
public class LoadTiqavService extends AbstractIntentService{

    @ServiceAction
    void loadNewest() {
        // サービスの中でやりたいこと
        // メソッドのパラメータには Parcelable, Serializable あるいはプリミティブな型を指定できる
    }
}

// 呼び出し側
LoadTiqavService_
                .intent(getContext())
                .loadNewest()
                .start();

デフォルトだと、 Intent インスタンスを作り Bundle にパラメータを指定し更に呼び出された側でも Bundle からパラメータを取り出したりと言ったコードが発生します。そう言った部分を省略できるメリットは大きいです。

ただし、 AndroidAnnotations は 今のところ kotlin と同居はできません。そのため、Activity,Fragment,Serviceといった AndroidAnnotations を利用したい箇所では Kotlin を使いませんでした。

ネットワーク通信

square/retrofit を利用しました。 kotlin から利用をしていると言って特に意識をする部分もありませんでした。

データベース

昨年、苦しめられた お世話になった realm を利用しました。kotlin で Realm にマッピングされるクラスを書く場合、

  • open なクラスにしなければならない
  • コンストラクタのフィールドは var にしなければならない

といったような注意事項がありました。また、RealmObjectのサブクラスはメソッドの追加、継承ができません。そのため、Nullablegetterを生やすとかそう言ったことができず、なんか kotlin っぽくない(?)感じになりました。

public open class Tiqav(@PrimaryKey public open var id : String = "",
                        public open var ext : String = "",
                        public open var height : Int = 0,
                        public open var width : Int = 0,
                        @SerializedName("source_url") public open var sourceURL : String = ""
                  ) : RealmObject() {}

そういえば、拡張関数は試してないのですが RealmObject のサブクラスに対しても拡張とかってできるんでしょうかね?

JSONパーサー

Realm を利用している関係上、公式サイトにサンプルも掲載されている google/gson を利用しました。これも kotlin から利用する上でそんなに困ることも無かったです。

DI

コンポーネントのテストを行う際、 Realm や Retrofit のサービスを依存性の注入によって参照させてあげるとテスト用の物が利用できて便利です。AndroidAnnotations にも DI のための機能は一応ありますがテストとの相性が良くないので、 google/dagger2 を利用しました。

Realm のインスタンスを作るために必要な RealmConfiguration や、 Retrofit のサービスを Activity/Fragment/Service などのコンポーネントにDIします。

テスト

CI環境を構築してテストの実行を想定した場合、エミュレーターによるテストは正直なところ現実的ではありません。そこで、 robolectric/Robolectric でテストを行います。その際、 Realm のモックが必要となるので、 jayway/powermock を使いました。

テストについては kotlin で記述を行いました。細かいところですがモックを作成するときに利用する when メソッドや、アサーションに使うisですが、 kotlin では予約語として存在するため whenis と、バッククォートでくくってあげる必要がありました。

また、@Ruleアノテーションについても @get:Rule とする必要があります。

まとめ

個人的な感想ですが、Androidではやはりコンポーネント間通信にかかるコードが長いイメージがあり、そのためそのあたりの削減には AndroidAnnotations が適していると感じました。

Kotlin を利用することで無名関数などの記法が楽になったり、あるいは Nullable を利用してより安全なコードを書くことができたりとメリットはあります。しかし、AndroidAnnotations の便利さを知っていると、 Kotlin が万能とは言い難い感じでした。

kotlin から AndroidAnnotations が使えたら最強なのかもしれない・・・。

Android のコンポーネントから独立をしている部分とかについては、 kotlin で書くとスマートになると思います。

余談

昔、Scala で Android アプリを書いた時にも似たようなことを思ったものだ・・・。

21
22
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
22