Androidアプリ開発&kotlin初心者がストップウォッチアプリ作成

Androidアプリ初心者がストップウォッチアプリ作成
  • URLをコピーしました!
※当ブログではアフィリエイト広告を表示しています
まゆみ

Pythonでブログ検索順位取得ツールを作るのが上手くいったし、次はゲームかなんか作ろうかな~

と、いい気になって考え出しました、まゆみです。

Pythonでゲームを作ることもできるようですが、

まゆみ

どうせなら、娘に遊んでもらえるようにアプリにしよう!

と考え付きまして、この度Andoroidアプリ開発を始めることにしました!

Andoroidアプリ開発といえば、Android Studioが必須。

以前、夫たんたんがMacにAndroid Studioを導入して記事にしていました。

が、私のPCはWindowsなので、Android Studioの導入や設定を以下の書籍を参考に行いました。

開発環境を以下にまとめておきます。

  • windows10 64bit
  • Intel Core i-5
  • メモリ8GB
  • Android Studio 3.4.2
  • 言語:kotlin
  • AVD(仮想端末):Nexus 5X , API level 27(←参考書籍で紹介されていたのを選んだ)

今回は、初心者が必ずと言ってもいいほど作るであろう、「ストップウォッチ」を作ってみました。

初めてのアプリ開発。
上手くいくのでしょうか・・・?

目次

ストップウォッチアプリ作成:参考のソースをそのまま作ってみた結果

参考書籍の通りにAndroid Studioを設定し、「Hello World!」の表示まではすんなり終わりました。

何か作ってみたいと思い、以下の参考HPで紹介されていたストップウォッチアプリを作ってみることにしました。

以下のソースコードは、参考HPのをそのまま書き写したものです。
説明は参考HPでご覧ください。

写しただけで、自分でアレンジしてないので、すんなり実行できると思ったのですが、思わぬエラーが出てしまいました。

package com.example.myapplication

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.TextView

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.startButton) as Button
        val stopButton = findViewById(R.id.stopButton) as Button
        val resetButton = findViewById(R.id.resetButton) as Button

        /* 1秒ごとに処理を実行する */
        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)
            }
        }

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

    // 数値を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)
        }
    }
}

ビルドしたら1件エラーが出てしまいました。

10行目のHandlerの箇所でエラーになっています。

メッセージに出ている「Task:app:buildInfoGeneratorDebug」で検索しても、良い情報は出てこず・・・

しかし、「Unsolved reference」の方で検索してみたら解決しました。

kotlin ビルドエラー
ビルドエラーがでた

エラー対応

ビルドエラー「 Unsolved reference : Handler 」の原因。

それは、

必要なHandlerクラスをインポートしていなかった!

でした。

根本的なところ・・・

というわけで、以下の一文を追加

import android.os.Handler

するとビルドはエラーが無くなりうまくいきましたが、エミュレータに表示された画面がこちら↓

Androidアプリ開発 ボタンの位置が想定と違う
ボタンの位置が想定と違う場所になった

ボタンの位置がおかしい。

activity_main.xmlでボタンの位置を設定し直します。

どうも「STOP」と「RESET」の上側の余白の設定ができていなかったので、時刻表示のテキストからの幅を指定しました。
その際、ボタンの上側と時刻テキストの下側を矢印で繋げないと上手く設定できないので注意です。

Androidアプリ開発 ボタンの配置設定
ボタンの配置を再設定(時刻とボタンの間を矢印で繋ぐ)

ボタンの配置を再設定した後の実行画面はこちら↓

Androidアプリ開発 ボタンの位置正常版
ボタンの位置が整った

上手く配置できています。

完成したストップウォッチアプリ(1秒間隔)

作成したストップウォッチアプリの動作をGIF動画でご覧ください。

Androidアプリ開発 ストップウォッチアプリ動画
ストップウォッチアプリの動作の様子

(たぶん)ちゃんと時間を計れています。

これで完成☆

ミリ秒に対応させよう

ストップウォッチアプリが動くところを見た夫たんたんが、

たんたん

ミリ秒も表示してよ!

と言ってきました。

まぁ確かにストップウォッチと言えばミリ秒も表示されているなぁ。
ということで、ミリ秒も表示できるようにしてみました。

ソースコード

ミリ秒に対応させたソースコードはこちらです。

これ以外に、画面の時刻表示のデフォルトテキストを「00:00:00.00」に修正しました。

表示は10ミリ秒までの表示にしています。

package com.example.myapplication

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import android.os.Handler

class MainActivity : AppCompatActivity() {

    val handler = Handler()  //一度だけ代入
    var timeValue:Long = 0       //何度も代入
    val interval:Long = 50       //msec


    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.startButton) as Button
        val stopButton = findViewById(R.id.stopButton) as Button
        val resetButton = findViewById(R.id.resetButton) as Button

        /* 1秒ごとに処理を実行する */
        val runnable = object : Runnable {
            override fun run() {
                timeValue++
                // TextViewを更新
                // ?.letを用いて、nullではない場合のみ更新
                timeToText(timeValue*interval)?.let{
                    // timeToText(timeValue)の値がlet内ではitとして使える
                    timeText.text = it
                }
                handler.postDelayed(this, interval)
            }
        }

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

    // 数値を00:00:00形式の文字列に変換する関数
    // 引数timeにはデフォルト値0を設定、返却する型はnullableなString?型
    private fun timeToText(time: Long = 0): String? {
        // if式は値を返すため、そのままreturnできる
        return if (time < 0) {
            null
        } else if (time.toInt() == 0) {
            "00:00:00.00"
        } else {
            /* msec */
            val h = time / 3600000
            val m = (time % 3600000) / 60000
            val s = ((time % 3600000) % 60000) / 1000
            val ms = (time  % 1000) / 10    //表示用にさらに10で割る
            "%1$02d:%2$02d:%3$02d.%4$02d".format(h,m,s,ms)
        }
    }
}

1ms,10ms間隔だと、上手くいかなかった

実は、1ミリ秒間隔や10ミリ秒間隔で動作させてみると上手くいきませんでした。

むっちゃ遅いのです。

ストップウォッチの1秒が通常の3秒くらいになってしまいました。

CPUの問題なのか?何なのか?

ひとまず、50ミリ秒間隔でやってみたら、それなりに時間を計れるようになったので、これで良しとしました。

50ミリ秒間隔でカウントしたストップウォッチアプリの動作はこちらのGIF動画でごらんください↓。

Androidアプリ開発 ミリ秒も表示したストップウォッチアプリ動画
ミリ秒も表示したストップウォッチアプリ(50msごとにカウント)

アプリ開発もkotlinも初めてでしたが、HPを参考にしまくってストップウォッチアプリを作ることができました。
あまり理解できてないけど(汗)

参考書籍やHPなどでもっとアプリ制作を学んで、オリジナルのアプリを作ってみたいです。

今思い描いているのは、娘向けの知育ゲームアプリ。

Androidアプリ開発/kotlinの勉強の様子を、また記事にまとめていきます。

んじゃ、また~

おススメのプログラミング独学方法はこちらの記事にまとめました!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

関連記事

応援よろしくお願いします☆

この記事を書いた人

理系夫婦の妻のほうです。
大学、大学院(修士)で物理を専攻。
2016年に長女を出産、2021年に長男を出産。
フルタイム勤務ワーママ→休職→専業主婦。

コメント

コメントする

目次