このすみノート

Webエンジニアが技術や趣味を書くブログです。

KotlinをAndroid Studio 3.0 Beta 6 でやってみた!

Kotlinが正式採用されるのを機に、Androidアプリ開発に試しに挑戦してみました。

内容としては、以下の「エンジニアHub 」の記事を試してみました!というお話です。

employment.en-japan.com

Android Studio 3.0 Beta 6 が入る

このブログの執筆時点では、インストールをすると「Android Studio 3.0 Beta 6」が入ります。

f:id:konosumi:20170918005840p:plain

なお、Webサイト上からインストールした時点ではBeta 5だったのですが、Android Studio を起動したらアップデートを促されまして、Beta 6に更新されました。

エラーが発生する

意気揚々と、Viewを作成してMainActivityのコードをコピペして起動してみたのですが、エラーが発生しました。

(´_`。)グスン

Error:(7, 23) Unresolved reference: Handler
Error:(14, 32) Type inference failed: Not enough information to infer parameter T in fun <T : View!> findViewById(p0: Int): T!
Please specify it explicitly.
Error:(14, 63) Unresolved reference: TextView
Error:(15, 35) Type inference failed: Not enough information to infer parameter T in fun <T : View!> findViewById(p0: Int): T!
Please specify it explicitly.
Error:(15, 63) Unresolved reference: Button
Error:(16, 34) Type inference failed: Not enough information to infer parameter T in fun <T : View!> findViewById(p0: Int): T!
Please specify it explicitly.
Error:(16, 61) Unresolved reference: Button
Error:(17, 53) Unresolved reference: reset
Error:(17, 63) Unresolved reference: Button

f:id:konosumi:20170918004846p:plain

(注釈:Unresolved reference: resetは、ViewのIDを間違えただけの私の凡ミスです。)

どうやってエラーを解決したのか、共有したいと思います。
(上級者であれば、すぐ直せるエラーばかりと思いますが。私自身が初心者ですので、あくまで初心者向けの内容です)

1. importがないと動かない

第一の原因として、import が不足していたため、クラスの解決ができておりませんでした。そのため、以下を追加しました。

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
import android.widget.TextView
import android.widget.Button

import文を追加して、必要なクラス(モジュール?)を取り込むとエラーが解消されます。

尚、使用していない未使用のモジュールは以下のように薄黒くハイライトされます。ハイライトされたimportは無駄なimportですので、削除しました。

f:id:konosumi:20170918010544p:plain

2. findViewByIdの書き方が異なる

第二の原因として、findViewByIdの書き方でエラーが発生しました。以下のように、findViewByIdで取得してasキャストする書き方はうまく動きません。

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 timeText = findViewById<TextView>(R.id.timeText)
val startButton = findViewById<Button>(R.id.start)
val stopButton = findViewById<Button>(R.id.stop)
val resetButton = findViewById<Button>(R.id.reset)

// もしくは
val timeText = findViewById<View>(R.id.timeText) as TextView

取得してから型をキャストするのではなく、取得時点で型を指定する必要があるみたいです。

完成版コード

エラーを修正したコードを載せておきます。

package <パッケージ名>

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
import android.widget.TextView
import android.widget.Button

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<View>(R.id.timeText) as TextView
        val timeText = findViewById<TextView>(R.id.timeText)
        val startButton = findViewById<Button>(R.id.start)
        val stopButton = findViewById<Button>(R.id.stop)
        val resetButton = findViewById<Button>(R.id.reset)

        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)
        }
    }
}

Kotlinについての所感

まだサンプルを起動しただけですので、Kotlinの深淵には全く触れておりません。

・・・とは言え、サンプルを見ただけでも「return if」は他の言語ではあまりない書き方ですし、目新しさを感じます。

Kotlinに興味が湧いてきました!

ただ、いくつか不満点をあげるとするならば、valとvarは一文字しか違わないので、見間違える気がしてなりません。あと、関数宣言がfunなのは、しばらく慣れそうもありません。普通ならfuncだと思うのですが、独特ですね。