[Android][Kotlin] KotlinでAndroidアプリケーションを記述する 01 [Hello Kotlin]

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは。こむろです。先日SAPを会場に行われたDevelopersIO 2015にお越しいただいた皆様、ありがとうございました。
自分は、引き続きこのブログでは統一感のあまりない雑多な技術記事を放出していこうかと思っていますので、よろしくお願いします。

Androidアプリケーション開発のAlternative開発言語として静かな注目を集めているKotlinについて調べてみました。

kotlin

Kotlinは、皆様ご存知の超有名IDEであるIntelliJ IDEAの開発元であるJetBrains社が開発しているプログラミング言語です。

スクリーンショット 2015-03-30 18.30.58

Wikipediaの説明を見てみると、

オペーレーティング・システムによらずJava仮想マシン上で動く。Java言語が書かれたプログラムと同じほど速くコンパイルされ同じほど速く動作するとしている。

とあります。
Javaと非常に親和性が高いようです。さらにこの言語を使ったAndroidアプリケーションの開発も可能なようです。今までのAndroidアプリケーション開発ではJava6(部分的にJava7)でしたが、色々と限界が見えてる昨今。AlternativeなAndroidアプリケーション開発言語として期待できそうです。

スクリーンショット 2015-03-30 18.31.39

気になったのが、

Java との相互運用性(Kotlin から Java を呼び出すことも、Java から Kotlin を呼び出すこともできる)

これならば部分的に導入することが出来るので、徐々にチーム内に侵食させることができそうです。

Kotlinを導入する

今回は、Android Studioにkotlinを導入してみます。自分の環境は以下のとおりです。

  • OS: Mac OSX Yosemite 10.10.2
  • IDE: Android Studio 0.8.9

早速Kotlinを導入してみましょう。

Pluginを追加する

Android Studio>Preferencesを選択し、設定画面を開きます。pluginを選択します。以下のような画面になるので、下のInstall JetBrains Pluginsをクリックします。

スクリーンショット_2015-03-31_14_13_58

Pluginブラウザが起動するので、kotlinを検索します。kotlinが検索されるので、Install Pluginをクリックします。

スクリーンショット 2015-03-31 14.25.22

スクリーンショット 2015-03-31 14.26.30

Yesをクリック。

スクリーンショット 2015-03-31 14.26.37

インストールが完了すると、再起動を要求されます。

スクリーンショット 2015-03-31 14.28.28

再起動します。

スクリーンショット 2015-03-31 14.29.54

これでkotlinの導入は完了です。

確認

確認してみます。適当なプロジェクトを作成します。
今回は「KotlinAndroid」という名前でAndroidプロジェクトを作成しましょう。今回はテンプレートを「Blank Activity with Fragment」を選択しました。

スクリーンショット 2015-03-31 14.42.36

さて、ここまではいつも通りです。ナビゲーションツリーで右クリックをしてメニューを表示、「New」を選択してみましょう。「kotlin File」が確認できます。

スクリーンショット 2015-03-31 14.44.04

とりあえず問題なくPluginは導入できたようです。

Java → Kotlin

KotlinのPluginを入れたお陰で、Javaファイルを一発で変換できる機能が追加されています。今作成したAndroidプロジェクトのActivityファイルをそのままKotlinに変換して試してみましょう。

Code>Convert Java File to Kotlin Fileを選択すると、変換が実行されます。

スクリーンショット_2015-03-31_14_58_12

変換後

package kotlin.android.classmethod.jp.kotlinandroid

import android.app.Activity
import android.app.Fragment
import android.os.Bundle
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup

public class MyActivity : Activity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_my)
        if (savedInstanceState == null) {
            getFragmentManager().beginTransaction().add(R.id.container, PlaceholderFragment()).commit()
        }
    }

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.my, menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        val id = item.getItemId()
        if (id == R.id.action_settings) {
            return true
        }
        return super.onOptionsItemSelected(item)
    }

    /**
     * A placeholder fragment containing a simple view.
     */
    public class PlaceholderFragment : Fragment() {

        override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle): View? {
            val rootView = inflater.inflate(R.layout.fragment_my, container, false)
            return rootView
        }
    }
}

かなり短くなりました。必要な部分だけ記述することが出来て非常に見やすくなっています。

javaパッケージをkotlinにリネームする

JavaファイルのConvertだけでは、そのまま実行することは出来ません。rootパッケージもきちんと変更してあげる必要があります。kotlinファイルは、javaパッケージ配下ではなく、kotlinパッケージ配下に配置する必要があります。

javaパッケージを右クリックしてリファクタメニューを表示します。

スクリーンショット 2015-04-09 16.09.29

javakotlinに書き換えてRefactorを実行します。

スクリーンショット 2015-04-09 16.11.12

build.gradleをKotlin用に設定する

kotlinパッケージ以下をコンパイル対象に含めるために、build.graldeを修正する必要があります。メニューから一発で全て設定してくれるので簡単です。

Tools>Kotlin>Configure Kotlin in Projectを選択します。

スクリーンショット 2015-04-09 16.19.25

これを選択すると自動的にbuild.gradleにKotlin用の設定が追記されます。

apply plugin: 'com.android.application'

// ↓追加された
apply plugin: 'kotlin-android'

android {
    compileSdkVersion 21
    buildToolsVersion "20.0.0"

    defaultConfig {
        applicationId "sample.android.classmethod.jp.kotlinandroid"
        minSdkVersion 18
        targetSdkVersion 21
        versionCode 1
        versionName "1.0"
    }

    // ↓追加された
    sourceSets {
        main.java.srcDirs += 'src/main/kotlin'
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    // ↓追加された
    compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}

// ↓追加された
buildscript {
    ext.kotlin_version = '0.11.91.1'
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}
repositories {
    mavenCentral()
}

プロジェクトをビルド

これでKotlinでAndroidアプリケーションを開発する準備ができました。プロジェクトをビルドします。

Build>Make Projectを選択します。

スクリーンショット 2015-04-09 16.26.10

Androidアプリケーションを実行する

ビルドに成功したらいつも通り、Androidアプリケーションを実行しましょう。正常に起動すれば以下の様な画面が表示されます。

device-2015-04-09-164145

以下のようなエラーが表示された場合は、一部ソースを修正する必要があります。

04-09 16:34:05.262  23786-23786/sample.android.classmethod.jp.kotlinandroid E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: sample.android.classmethod.jp.kotlinandroid, PID: 23786
    java.lang.RuntimeException: Unable to start activity ComponentInfo{sample.android.classmethod.jp.kotlinandroid/sample.android.classmethod.jp.kotlinandroid.MyActivity}: java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter savedInstanceState
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2237)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2286)
            at android.app.ActivityThread.access$800(ActivityThread.java:144)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1246)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:212)
            at android.app.ActivityThread.main(ActivityThread.java:5137)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:902)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:718)
            at dalvik.system.NativeStart.main(Native Method)
     Caused by: java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter savedInstanceState
            at sample.android.classmethod.jp.kotlinandroid.MyActivity$PlaceholderFragment.onCreateView(MyActivity.kt)
            at android.app.Fragment.performCreateView(Fragment.java:1700)
            at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:894)
            at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1066)
            at android.app.BackStackRecord.run(BackStackRecord.java:684)
            at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1455)
            at android.app.Activity.performStart(Activity.java:5240)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2210)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2286)
            at android.app.ActivityThread.access$800(ActivityThread.java:144)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1246)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:212)
            at android.app.ActivityThread.main(ActivityThread.java:5137)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:902)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:718)
            at dalvik.system.NativeStart.main(Native Method)

修正する箇所は、PlaceHolderFragment#onCreateView()です。以下のように修正してください。

/**
 * A placeholder fragment containing a simple view.
 */
public class PlaceholderFragment : Fragment() {

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val rootView = inflater.inflate(R.layout.fragment_my, container, false)
        return rootView
    }
}

修正した箇所は、savedInstanceState: Bundleです。この値はnullを許容する必要が有るため、値をNullableに変更する必要があります。「?」を付与します。これで正常に実行できると思います。

まとめ

Androidアプリケーションを今までJavaで書いていた人にとっても、かなり取っ付きやすい言語だという印象を受けました。また、Java8などを利用して、あの機能があったら良いのになぁと思うことがあると、さらに魅力的かもしれません。今後は少しずつKotlinでAndroidアプリケーションの方を記述していってみようかと思います。
今後は、Javaのソースコードと混在させて使う、Kotlinの言語としての特性などを調べていきたいと思います。非常に魅力的なプログラミング言語だと思います!ことりんかわいいよコトリン

参照