[Android] その会議いくら?を算出する

この記事を見てAndroid+Kotlin初心者の自分でも作れると思ったので作ってみました。
[Qiita]「その会議いくら?」を算出する(JavaScript)

環境

  • 開発環境 : Android Studio 3.4.1
  • 使用言語 : Kotlin 1.3.40
  • 実機環境 : Zenfone 5 (ZE620KL)

出来たもの

参考にしたサイト

やった事

  • ConstraintLayoutをトップとしてレイアウトを作成してみた。
  • Timerを使ってタイマー処理。
  • 非メインスレッドからメインスレッドUIの更新。

コード(レイアウト含む)

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    <TextView
            android:text="その会議いくら?"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/textView" app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="8dp"
            app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="8dp"
            app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="32dp" android:textSize="36sp"/>
    <LinearLayout
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" android:id="@+id/linearLayout4" android:layout_marginTop="8dp"
            app:layout_constraintTop_toBottomOf="@+id/textView" app:layout_constraintStart_toStartOf="parent"
            android:layout_marginStart="8dp" app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="8dp">
        <TextView
                android:text="人数 :"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:id="@+id/textView2"
                android:gravity="center_vertical"/>
        <SeekBar
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:id="@+id/numberOfPersonSeekBar"
                android:layout_marginStart="8dp"
                android:max="50"
                android:layout_weight="1"/>
        <EditText
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:inputType="number"
                android:ems="3"
                android:id="@+id/numberOfPersonEditText"
                android:textSize="24sp"
                android:layout_marginStart="8dp"/>
        <TextView
                android:text="人"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:id="@+id/textView7" android:textSize="24sp"
                android:layout_marginStart="8dp" android:gravity="center_vertical"/>
    </LinearLayout>
    <LinearLayout
            android:orientation="horizontal"
            android:layout_width="0dp"
            android:layout_height="wrap_content" android:layout_marginTop="64dp"
            app:layout_constraintTop_toBottomOf="@id/linearLayout4" app:layout_constraintEnd_toEndOf="parent"
            android:layout_marginEnd="8dp" app:layout_constraintStart_toStartOf="parent"
            android:layout_marginStart="8dp" android:id="@+id/linearLayout">
        <Button
                android:text="Start"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/startButton" android:layout_weight="1"/>
        <Button
                android:text="Stop"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/stopButton" android:layout_weight="1"/>
        <Button
                android:text="Reset"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/resetButton" android:layout_weight="1"/>
    </LinearLayout>
    <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" android:layout_weight="1"
            android:id="@+id/linearLayout3" android:layout_marginTop="64dp"
            app:layout_constraintTop_toBottomOf="@+id/linearLayout" android:layout_marginStart="8dp"
            app:layout_constraintStart_toStartOf="parent" android:layout_marginEnd="8dp"
            app:layout_constraintEnd_toEndOf="parent">
        <TextView
                android:text="経過時間 :"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/textView3" android:textSize="30sp" android:layout_weight="1"
                android:gravity="center"/>
        <TextView
                android:text="XXX 秒"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/elapsedTimeTextView" android:textSize="60dp" android:layout_weight="1"
                android:gravity="center"/>
    </LinearLayout>
    <LinearLayout
            android:orientation="vertical"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="8dp"
            app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="8dp"
            android:layout_marginTop="24dp" app:layout_constraintTop_toBottomOf="@+id/linearLayout3">
        <TextView
                android:text="コスト"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/textView4" android:textSize="30sp" android:layout_weight="1"
                android:gravity="center"/>
        <TextView
                android:text="X,XXX,XXX 円"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/costTextView" android:textSize="60sp" android:layout_weight="1"
                android:gravity="center"/>
    </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
package jp.session.kikikiroku.howmuchisthemeeting

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.SeekBar
import kotlinx.android.synthetic.main.activity_main.*
import java.util.*

class MainActivity : AppCompatActivity() {
    class CostTimerCallback(val costTimer: CostTimer) : TimerTask() {
        override fun run() {
            costTimer.update(1)
        }
    }
    class CostTimer(val activity: MainActivity) {
        private var timerInstance: Timer? = null
        private var usingSec: Long = 0
        fun start() {
            stop()
            timerInstance = Timer()
            timerInstance?.schedule(CostTimerCallback(this), 1000, 1000)
        }
        fun stop() {
            if(timerInstance != null) {
                timerInstance?.cancel()
                timerInstance = null
            }
            update(0)
        }
        fun reset() {
            usingSec = 0
            update(0)
        }
        fun update(addSec: Long) {
            usingSec += addSec

            // time
            activity.setElapsedTime(usingSec.toInt())

            // cost
            val averageMonthlyCost = 400000.0     // 40万/月
            val averageMonthlyWork = 160.0        // 160時間/月
            var costPerSecond = averageMonthlyWork * 3600 / averageMonthlyCost
            var person = Integer.parseInt(activity.numberOfPersonEditText.text.toString())
            var cost = (costPerSecond * usingSec * person).toInt()
            activity.setCost(cost)
        }
    }
    private val costTimer: CostTimer = CostTimer(this)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        numberOfPersonSeekBar.progress = 5
        // numberOfPersonSeekBar.min = 1
        numberOfPersonSeekBar.max = 20
        numberOfPersonSeekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
            override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
                // ツマミをドラッグしたときに呼ばれる
                numberOfPersonEditText.setText(progress.toString())
            }
            override fun onStartTrackingTouch(seekBar: SeekBar) {
                // ツマミに触れたときに呼ばれる
            }
            override fun onStopTrackingTouch(seekBar: SeekBar) {
                // ツマミを離したときに呼ばれる
            }
        } )
        numberOfPersonEditText.setText(numberOfPersonSeekBar.progress.toString())

        startButton.setOnClickListener{onClickStartButton()}
        stopButton.setOnClickListener{onClickStopButton()}
        resetButton.setOnClickListener{onClickResetButton()}

        setElapsedTime(0)
        setCost(0)
    }

    private fun setElapsedTime(timeSec: Int) {
        elapsedTimeTextView.post{elapsedTimeTextView.text = "%,d".format(timeSec.toLong()) + " 秒"}
    }
    private fun setCost(costYen: Int) {
        costTextView.post{costTextView.text = "%,d".format(costYen.toLong()) + " 円"}
    }

    private fun onClickStartButton() {
        costTimer.start()
    }
    private fun onClickStopButton() {
        costTimer.stop()
    }
    private fun onClickResetButton() {
        costTimer.reset()
    }
}

まとめ

  • Androidのタイマーは別スレッドなのでUI操作は注意する。
  • シークバーの最小値設定はAPI Level 26から。

希木小鳥

Diablo1でハクスラの世界に。今はBorderlands2をプレイ中。ぬるゲーマー。

あわせて読みたい