正式採用の「Kotlin」で挑戦! 初めてのAndroidアプリ開発 ~ストップウォッチを作ってみよう~
Kotlin入門者に向け、手を動かして学べるテキストをお届けします。Kotlinは、2011年7月に登場したモダンなプログラミング言語ですが、Androidアプリの開発言語として、Google I/O 2017で正式採用され、一挙に浸透してきました。本稿では、Kotlinの特徴を紹介し、簡単なAndroidアプリとしてストップウォッチを作ってみます。
アプリエンジニアの池田惇です。Google I/O 2017で、Androidの開発言語としてKotilnが正式に採用されました。少し前から業務でもKotlinを採用していたのでとても嬉しいです!
Android Developers Blog: Android Announces Support for Kotlin
Kotlinは、2011年7月に登場したモダンな言語です。モダンな言語を開発に使用すると、得られる知識の質が上がります。これからAndroidアプリ開発を始める方は、Kotlinを採用するのが良いでしょう。
本稿では、Kotlinの特徴を紹介し、簡単なAndroidアプリとしてストップウォッチを作ってみます。開発環境の構築から行いますので、Androidアプリ開発の経験がない方も手を動かしながら挑戦してみてください。
Kotlinの特徴
Kotlinは、JetBrainsが開発したプログラミング言語です。
- 行末のセミコロンが不要
- 静的型付け
- 型記述が省略可能(型推論)
- JVM(Java Virtual Machine、Java仮想マシン)上で動作する
- Javaコードと相互運用ができるため、Javaからの移行が容易
といった特徴があり、Javaよりも簡潔に記述できます。今後はAndroidアプリに限らず、サーバサイドのJavaも置き換えていくかもしれません。
開発に役立つ特徴をさらにいくつか紹介します。
valとvar
変数の定義には、val
とvar
の2つを使い分けます。val
は再代入ができず、var
は再代入可能です。
val a: String = "foo" a = "bar" // エラーになる var b: String = "foo" b = "bar" // エラーにならない
見通しの良いコードを書くには、可能な限りval
を使い、必要な場合のみvar
を使うのが良いでしょう。
nullable
null
を代入できる変数とできない変数は、別の型として区別されます。例えば、String
型であれば最後に?
をつけてString?
型として宣言しない限り、null
を代入することはできません。
val a: String = null // エラーになる val b: String? = null // エラーにならない
このように、意図しないnull
の代入はコンパイル時にエラーとなるため、NullPointerException
を防ぐ効果があります。
値を返すif式
Kotlinのif
はif文としてだけでなくif式としても使えます。つまり、値を返すことができます。
下記の例のように、簡潔に書ける場面が多くて便利です。
// Javaだとこうなる String a; if(b) { a = "foo"; } else { a = "bar"; }
// Kotlinならこのように書ける val a = if(b) "foo" else "bar"
名前付き引数、デフォルト引数
Kotlinでは、引数に名前をつけたり、デフォルト値を与えることができます。このため、オーバーロード(多重定義、引数や戻り値が異なる同一名称のメソッドを複数定義すること)を使わずに済みます。
// middleNameにはデフォルト値を設定 fun fullName(firstName: String, middleName: String = "", lastName: String) // 必要な引数のみ指定して渡すことができる val name = fullName(firstName = "Jun", lastName = "Ikeda")
開発環境を整えよう
ダウンロードとインストール
Androidアプリの開発環境「Android Studio」は、3.0から正式にKotlinに対応しています。
Android Studio と SDK ツールをダウンロードする | Android Studio
ダウンロードしたZIPファイルを解凍してインストールしましょう。
Android Studioを起動すると、ウィザードが開始されるので、SDKのダウンロードなど初期設定を進めます。少し時間がかかるので、気長に待ちましょう。既に別バージョンのAndroid Studioをインストールしてあれば、設定を引き継ぐこともできます。
ウィザードを開始
初期設定が終わると、次のようなウィンドウが表示されます。[Start a new Android Studio project]を選択します。
プロジェクト名など
選択すると、ウィザードが現れます。
[Application name]はプロジェクト名、[Company domain]はパッケージの階層を示します。他のアプリとの重複を防ぐため、ストアに公開する場合は、自前のドメインを入力してください。
Kotlinで開発しますので、[include Kotlin support]をチェックします。
対象のプラットフォーム
次に、対象のプラットフォームを設定します。
スマートフォン用のアプリを開発するときは、[Phone and Tablet]のみ選択します。[Minimum SDK]で、対象とする下限のOSバージョンを選択しましょう。今回は、安定性が高く開発しやすい環境としてOS 5.0以上を対象とし、API 21を選びます。
コンポーネント
Androidの画面は、Activityというコンポーネントで構成されます(実際のアプリでは、FragmentやViewと組み合わせて画面を構成します)。
今回は、[Empty Activity]を選択します。
次画面のActivity名設定は、デフォルトの「MainActivity」のままでOKです。
ここまででプロジェクトの作成は完了です。
ビルドしてみると
ビルドすると、以下のようなエラーが出るかもしれません。
この場合は必要なSDKが不足しているので、[Install missing platform(s) and sync project]をクリックし、表示された内容にしたがってインストールしましょう。
エミュレーターの準備
上部のツールバーからAVD Managerを起動します。
[Create Virtual Device]を選択して、新しくエミュレーターを作成します。
今回は[Phone]の[Nexus 5X]を準備します。[System Image]の選択により、OSが決まります。ここではAndroid 7.0 Nougatにします。
アプリを実行する
上部のツールバーからアプリを実行します。
先程作成したエミュレーターを選択しましょう。
アプリが起動できました。
以上で、開発環境の構築は完了です。
ストップウォッチアプリを作ってみよう
準備した開発環境をさっそく使ってみましょう。簡単なAndroidアプリの例として、ストップウォッチアプリを作ってみます。
レイアウトの作成
まずは、時間を表示するTextViewや、操作のためのButtonを配置しましょう。activity_main.xml
ファイルを開き、[Design]タブを使って、レイアウトを作成していきます。
時刻を表示するTextViewを準備
最初から配置してある「Hello World!」のTextViewを選択し、右側の[Properties]から[id]に「timeText」、[text]に「00:00:00」、[textSize]に「60sp」を設定します。
ボタンを配置
左側の[Palette]から[Button]をドラッグ・アンド・ドロップして配置します。開始・停止・リセットの3つのボタンを配置しましょう。先ほどと同様に[Properties]から、[id]と[text]をそれぞれ「start」「stop」「reset」としてください。
各ボタンのレイアウトを調整します。右側の[Properties]を使い、上と左右のマージンを32dpに調整しましょう。
ロジックの実装
先ほど紹介したKotlinの特徴をいくつか使って、ロジックを実装しましょう。
今回は、すべてMainActivity.kt
に記述します。
配置したView要素にアクセス
先ほど配置した時刻表示のTextViewと3つのボタンを、変数に代入します。
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // View要素を変数に代入 val timeText = findViewById(R.id.timeText) as TextView val startButton = findViewById(R.id.start) as Button val stopButton = findViewById(R.id.stop) as Button val resetButton = findViewById(R.id.reset) as Button }
1秒ごとに数値を加算する
Handler
とRunnable
を使って、1秒ごとにtimeValue
を1増やします。val
とvar
をそれぞれ使いました。
// 1度だけ代入するものはvalを使う val handler = Handler() // 繰り返し代入するためvarを使う var timeValue = 0 override fun onCreate(savedInstanceState: Bundle?) { /* 中略 */ // 1秒ごとに処理を実行 val runnable = object : Runnable { override fun run() { timeValue++ handler.postDelayed(this, 1000) } } }
TextViewの表示を更新する
timeValue
の値を、timeText
に反映させます。
関数timeToText()
の引数time: Int
は、デフォルト値0
を持っています。また、返却する型はnullableなString?
型にしました。引数の値が不正な場合はnull
を返すようにしています。
override fun onCreate(savedInstanceState: Bundle?) { /* 中略 */ val runnable = object : Runnable { override fun run() { timeValue++ // TextViewを更新 // ?.letを用いて、nullではない場合のみ更新 timeToText(timeValue)?.let { // timeToText(timeValue)の値がlet内ではitとして使える timeText.text = it } handler.postDelayed(this, 1000) } } } // 数値を00:00:00形式の文字列に変換する関数 // 引数timeにはデフォルト値0を設定、返却する型はnullableなString?型 private fun timeToText(time: Int = 0): String? { // if式は値を返すため、そのままreturnできる return if (time < 0) { null } else if (time == 0) { "00:00:00" } else { val h = time / 3600 val m = time % 3600 / 60 val s = time % 60 "%1$02d:%2$02d:%3$02d".format(h, m, s) } }
ボタンを押した時の処理を実装
3つのボタンの処理をそれぞれ実装します。
override fun onCreate(savedInstanceState: Bundle?) { /* 中略 */ // start startButton.setOnClickListener { handler.post(runnable) } // stop stopButton.setOnClickListener { handler.removeCallbacks(runnable) } // reset resetButton.setOnClickListener { handler.removeCallbacks(runnable) timeValue = 0 // timeToTextの引数はデフォルト値が設定されているので、引数省略できる timeToText()?.let { timeText.text = it } } }
完成!
ここまでで実装は完了です。
コード全体は、以下のようになります。
class MainActivity : AppCompatActivity() { val handler = Handler() var timeValue = 0 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val timeText = findViewById(R.id.timeText) as TextView val startButton = findViewById(R.id.start) as Button val stopButton = findViewById(R.id.stop) as Button val resetButton = findViewById(R.id.reset) as Button val runnable = object : Runnable { override fun run() { timeValue++ timeToText(timeValue)?.let { timeText.text = it } handler.postDelayed(this, 1000) } } startButton.setOnClickListener { handler.post(runnable) } stopButton.setOnClickListener { handler.removeCallbacks(runnable) } resetButton.setOnClickListener { handler.removeCallbacks(runnable) timeValue = 0 timeToText()?.let { timeText.text = it } } } private fun timeToText(time: Int = 0): String? { return if (time < 0) { null } else if (time == 0) { "00:00:00" } else { val h = time / 3600 val m = time % 3600 / 60 val s = time % 60 "%1$02d:%2$02d:%3$02d".format(h, m, s) } } }
エミュレーター上でアプリを実行して、動作を確認しましょう。
今回のアプリは練習用のため、最低限の実装にとどめています。興味がある方は、さらに以下の点に取り組んでいただけると良いでしょう。
- Android開発用のプラグインKotlin Android Extensionsを使って、
findViewById
を省略する - 関数の引数や返却値をnullableにすべきかどうか再考する
もっと学ぶには
Kotlinの知識を深めるために、参考になる書籍やサイトを紹介していきます。
書籍で体系的に学ぶには『Kotlinスタートブック』がおすすめ
長澤太郎『Kotlinスタートブック』(リックテレコム、2016年)では、基本的な文法からAndroidアプリの開発方法まで幅広く学べます。日本語でKotlinについて書かれた書籍はまだまだ少ないため、貴重な一冊と言えるでしょう。
Kotlinスタートブック 新しいAndroidプログラミング - リックテレコム 書籍情報
また、日本Kotlinユーザグループが、電子書籍『Kotlin入門までの助走読本』(PDF)を2017年5月29日に公開しています。
kotlin-prior-learning-book.pdf - Google ドライブ
オンラインで問題を解いて学ぶ
Kotlin開発元のJetBrainsが提供するTry Kotlinでは、Webブラウザ上でKotlinを実行することができます。
Kotlin Koansと呼ばれる全42問の問題を解いていけば、Kotlinの基礎や特徴が学べるようになっています。
各問題には、参考とすべき公式ドキュメントへのリンクが載せてあります。例えば7問目の「Introduction - Data classes」であれば「classes」「properties」「data classes」の3つのリンクが貼られています。実際に問題を解きながら必要な箇所のドキュメントを効率よくチェックできるため、やる気もキープしやすいのではないでしょうか。
おわりに
Kotlinの特徴を紹介し、開発環境を整えて簡単なAndroidアプリを作ってみました。
Androidアプリの開発では、今後はKotlinを使う場面が増えてくると思います。モダンな言語を使うことで開発効率が上がったり、エンジニアとしての学びも増えます。積極的に導入してはいかがでしょうか。
著者プロフィール
池田 惇(いけだ・じゅん)@jun_ikd