はじめに
こんにちは、アプリケーションエンジニアのid:takuji31です。今年の1月に入社してAndroidアプリの開発を行っています。
先週4月2日(土)にはてな京都オフィスで開催されたKotlin 1.0.0リリース記念勉強会 in 京都で、「KotlinとモダンなライブラリーでAndroidアプリを作るっ」というタイトルで発表しました。
この発表では、AndroidアプリをKotlinを使って作る時に既存のライブラリーを使うことができるか、使う場合にKotlinの利点をどう活かすか、という点について話しました。
Kotlinとは
KotlinはJetBrainsが開発しているJVM言語です。Javaとの100%の相互互換性を目指しつつモダンな言語機能を取り入れた言語で、最近は特にAndroid関連のサポートを強化していて、Androidアプリ開発で多く利用されはじめています。
発表資料
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だと以下のようになります。
@Module class 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勉強会や以下のエントリーで紹介していますので、そちらをご覧ください。
あとがき
Kotlin1.0.0がリリースされ、プロダクションへの導入がかなり現実的になってきました。
はてなでも導入を検討していますが、まだ具体的な予定はありません。
JillやAndroid Lint、Instant Runなど最新の環境への対応も進められているので、Javaと遜色なくAndroidアプリを作ることができるでしょう。
はてなではAndroidやiOSのネイティブアプリ開発を行うスマートフォンエンジニアの募集を行っています。
一緒に最高のモバイルアプリを作りましょう!