【Android】KotlinのCountDownTimerを用いた時分秒タイマー

# はじめに
今回はKotlinのライブラリCountDownTimerを用いて、より実用性の高いタイマーを作りました。
時分秒表示やストップボタン、リセットボタンを実装してあります。
参考：[CountDownTimer公式ドキュメント](https://developer.android.com/reference/kotlin/android/os/CountDownTimer)

ソースコードは[こちら](https://github.com/noodle2290/NeoCountDownTimer)から

![Screenshot_20220512_015704.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/962236/dc639120-966a-d8e3-71cb-c56420bb58e8.png)


# 環境
+ Android Studio Bumblebee | 2021.1.1.patch3
+ targetSDK: 32
# 概要
1. View Bindingの設定
2. レイアウトの作成
3. 初期状態の作成
4. スタートボタンの作成
5. ストップボタン、リセットボタンの作成
6. 完成

## 1. View Bindingの設定
### build.gradleのandroidに以下のコードを追加します
```kotlin:build.gradle
    kotlinOptions {
        jvmTarget = '1.8'
    }
    //ここから
    buildFeatures{
        viewBinding true
    }
```
### MainActivity.ktに以下のコードを追加します
```kotlin:MainActivity.kt
class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater).apply { setContentView(this.root) }
    }
}
```
これでView Bindingの設定は終わりです。

## 2. レイアウトの作成
レイアウトはシンプルにテキストビュー1つとボタン3つにします。
```xml:activity_main.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/time_text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="240dp"
        android:text="00"
        android:textSize="60sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/start_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:text="スタート"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/time_text_view" />

    <Button
        android:id="@+id/stop_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:text="ストップ"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/start_button" />

    <Button
        android:id="@+id/reset_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:text="リセット"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/stop_button" />
</androidx.constraintlayout.widget.ConstraintLayout>
```

## 3. 初期状態の作成
時間、分、秒を設定しテキストビューに表示します。
この際見やすいようにpadStartメソッドを使用して0埋めを行いました。
```kotlin:MainActivity.kt
        binding = ActivityMainBinding.inflate(layoutInflater).apply { setContentView(this.root) }

        //ここから
        val hour:Long = 0
        val minute:Long = 5
        val second:Long = 0

        binding.timeTextView.text = "${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}:${second.toString().padStart(2, '0')}"

        var secondAll: Long = hour * 3600 + minute * 60 + second

        binding.stopButton.isVisible = false
```

## 4. スタートボタンの作成
スタートボタンのクリックリスナーを実行します。この際CountDownTimerを定義しますが、他のクリックリスナーでも使うのでlateinitで先に定義しておいてください。
```kotlin:MainActivity.kt
    private lateinit var binding: ActivityMainBinding
    private  lateinit var timer: CountDownTimer //ここを追加

    ~

        binding.stopButton.isVisible = false
        //ここから
        binding.startButton.setOnClickListener {
            binding.startButton.isVisible = false
            binding.stopButton.isVisible = true
            timer = object : CountDownTimer(secondAll * 1000, 1000) {
                override fun onFinish() {
                    binding.startButton.isVisible = true
                    secondAll = hour * 3600 + minute * 60 + second
                    binding.timeTextView.text = "${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}:${second.toString().padStart(2, '0')}"
                }

                override fun onTick(millisUntilFinished: Long) {
                    secondAll--
                    binding.timeTextView.text = "${(secondAll / 3600).toString().padStart(2, '0')}:${((secondAll % 3600) / 60).toString().padStart(2, '0')}:${((secondAll % 3600) % 60).toString().padStart(2, '0')}"
                }
            }
            timer.start()
        }
```

## 5. ストップボタン、リセットボタンの作成
残り2つのボタンの処理も実装します。

```kotlin:MainActivity.kt
        binding.stopButton.setOnClickListener {
            binding.startButton.isVisible = true
            binding.stopButton.isVisible = false
            timer.cancel()
        }

        binding.resetButton.setOnClickListener {
            timer.cancel()
            binding.startButton.isVisible = true
            binding.stopButton.isVisible = false
            binding.timeTextView.text = "${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}:${second.toString().padStart(2, '0')}"
            secondAll = hour * 3600 + minute * 60 + second
        }

```

## 6. 完成
あとはお好みでエディットテキストを用いて設定時間を変更できるようにしたり、終了時に音が鳴るようにするなど。
余談ですがCountDownTimerは誤差が大きく、正確な時間を測るには向いていないそう...
非同期処理を用いると良いそうなのでいつかちゃんと書きたい