Kotlinでモダンなライブラリーを駆使してAndroidアプリを開発する

はじめに

こんにちは、アプリケーションエンジニアのid:takuji31です。今年の1月に入社してAndroidアプリの開発を行っています。

先週4月2日(土)にはてな京都オフィスで開催されたKotlin 1.0.0リリース記念勉強会 in 京都で、「KotlinとモダンなライブラリーでAndroidアプリを作るっ」というタイトルで発表しました。

この発表では、AndroidアプリをKotlinを使って作る時に既存のライブラリーを使うことができるか、使う場合にKotlinの利点をどう活かすか、という点について話しました。

Kotlinとは

KotlinはJetBrainsが開発しているJVM言語です。Javaとの100%の相互互換性を目指しつつモダンな言語機能を取り入れた言語で、最近は特にAndroid関連のサポートを強化していて、Androidアプリ開発で多く利用されはじめています。

発表資料

speakerdeck.com

Kotlinを選ぶ理由

ひとことでまとめると「モダンな言語機能をAndroid開発で"複数の観点から現実的に"利用できる」ではないでしょうか。

シンタックスがOSバージョンに依存しない

Android JavaはJava 6にJava 7の一部シンタックスを追加した「Java 6のようなJava 7のようなJavaではない何か」です。

もちろんJava 8で追加されたラムダ式、メソッドリファレンスやStream API等はAndroid Javaでは(通常の方法では)利用できません。

先日発表されたJack&JillでJava 8相当の機能が一部できるようになりましたが、そのうちのいくつかはAndroid N以降でのみ利用可能です。

Kotlinにも同等の機能はありますが、Java 6相当のバイトコードを生成しますので、もちろん古いバージョンのAndroidでも動くコードが書けます。

少ないメソッド数とファイルサイズ

Kotlinの標準ライブラリーは多くがinline functionで定義されているので、Androidのメソッド数制限に優しいです。

1.0.0の時点でメソッド数はおよそ7000です、一般的なライブラリーと比べるとかなり多いですが、言語としてこの数はさほど多くないのではないでしょうか。

ライブラリーのjarも900KB弱とJVM言語としてはかなり小さいです。

JVM言語である

(AndroidにJVMは搭載されていませんが)JVM言語であることで、Android Javaとの高い互換性を保っていると考えます。

いきなりAndroidのコードをSwiftで書く、といったようなアプローチよりはかなり現実的に感じます。

Kotlinで既存のJavaライブラリーを使う

Kotlinの記法を最大限利用してスッキリ書く

KotlinでAndroidアプリを書く時の懸念点の一つとして「Javaで書かれたJavaライブラリーやAndroidライブラリーは正しく使うことができるのか」が挙げられます。

ほとんどのライブラリーはKotlinでもそのまま動きます。

発表資料ではKotlinの機能を活用することで、ライブラリーを使ったコードをスッキリ書けるようにしています。

例えばDagger2のModuleは、PropertyやPrimary constructorを使うことで、コードを短くすることができます。

@Module
public class AppModule {

    private final Context context;

    public AppModule(Context context) {
        this.context = context;
    }

    @Provides
    public Context getContext() {
        return context;

    }

    @Provides
    public NotificationManager notificationManager(Context context) {

        return (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

    }
}


上記のJavaコードに相当するものはKotlinだと以下のようになります。

@Moduleclass AppModule(@get:Provides val context: Context) {

    @Provides
    fun notificationManager(context: Context): NotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

}

単純なデータクラスはdata modifierをつけてやることで簡単に定義できます。

public class User {
    @NonNull
    private final String name;
    @Nullable
    private final String birthDay;

    public User(@NonNull String name, String birthDay) {
        this.name = name;
        this.birthDay = birthDay;
    }

    @NonNull
    public String getName() {
        return name;
    }

    @Nullable
    public String getBirthDay() {
        return birthDay;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof User)) return false;

        User user = (User) o;

        if (!name.equals(user.name)) return false;
        return birthDay != null ? birthDay.equals(user.birthDay) : user.birthDay == null;

    }

    @Override
    public int hashCode() {
        int result = name.hashCode();
        result = 31 * result + (birthDay != null ? birthDay.hashCode() : 0);
        return result;
    }
}

単純なことがやりたいだけなのに、Javaだと(最近はIDEが自動生成してくれるとはいえ)かなり長い鉄板コードが必要ですね。

data class User(val name: String, val birthDay: String?)

Kotlinだとかなりスッキリ書くことができました!

Android公式のData Binding Libraryも一部を除いてKotlinと一緒に利用できます。

Javaとの相互運用性が高いので、「Kotlinでどうしても書けない部分はJavaで書く」ということもできます。

Null Safetyについて

Kotlinの長所の一つとしてNull Safetyが挙げられますが、この利点はJavaで書かれたコードでも利用できます。

@NonNull(@NotNull)/@NullableなどのアノテーションをJavaコードで付与することで、Kotlin側でNullableな型であるかどうか判定できます。

また、Kotlinで書かれたコードをJavaから使う時にも@NonNull(@NotNull)/@Nullable相当に変換され、IDEで警告が表示されるようになります。

@NonNull(@NotNull)/@Nullableアノテーションは、org.jetbrains.annotations パッケージやAndroid Support Annotationのアノテーションを使うことができます。

ただし、KotlinからJavaコードを利用する場合は付与されているアノテーション通りにコードが動いている必要がありますし、JavaからKotlinのコードを利用する場合はNonNullならNonNullであることをコードで保証してやらないと、例外が発生することがありますので、注意が必要です。

KotlinでKotlinのライブラリーを使う

Kotlinで書かれているライブラリーを利用することで、Kotlinの機能を最大限に活かすことができます。

また、JavaのライブラリーのExtensionをExtension functionやExtension propertyを利用して作ることで、コード量を更にスッキリさせることもできます。

発表資料では2つのライブラリーを紹介しています。

Anko

AnkoはKotlinを開発しているJetBrains製の、Android向け便利ライブラリーです。

レイアウトをDSLで書く機能や、Androidコンポーネントの拡張、SQLiteのヘルパーなどが含まれます。

GitHub - Kotlin/anko: Pleasant Android application development

レイアウトのDSLはコードでとても簡単にレイアウトを作成でき、更にXMLよりパフォーマンスもよい等のメリットがありますが、コードで表現するため、デザイナーがXMLを触ってデザインを作るといった環境での使用は難しそうです。また、Android公式のData Binding Libraryとは併用できません。

Androidコンポーネントの拡張は、わずらわしいActivityやServiceの開始処理を1メソッドで書けるようになったり、ExtraありのIntentを簡単に生成できるようになります。

便利な上に、コンポーネント化されていますので、必要なものだけ依存関係に追加して使うとよいでしょう。

Koreference

Koreferenceは拙作のライブラリーで、AndroidのSharedPreferencesを簡単に扱えるものです。

GitHub - takuji31/Koreference: Android SharedPreference delegate property for Kotlin

Delegated propertyの機能を利用することで、モデルクラスにPropertyを定義するだけでSharedPreferencesに対して値をget/setできます。

Koreferenceの使い方については、過去に関西モバイルアプリ研究会や関西Kotlin勉強会や以下のエントリーで紹介していますので、そちらをご覧ください。

blog.takuji31.jp

あとがき

Kotlin1.0.0がリリースされ、プロダクションへの導入がかなり現実的になってきました。

はてなでも導入を検討していますが、まだ具体的な予定はありません。

JillやAndroid Lint、Instant Runなど最新の環境への対応も進められているので、Javaと遜色なくAndroidアプリを作ることができるでしょう。

はてなではAndroidやiOSのネイティブアプリ開発を行うスマートフォンエンジニアの募集を行っています。

一緒に最高のモバイルアプリを作りましょう!

hatenacorp.jp