くやしいのでAndroidStudioでストップウォッチ作る

リバーシの時間表示の時、訳わかんなくて悔しかったので、ストップウォッチ単体で作ってみる。つっても大体コピペコード。

ストップウォッチ色々

Handlerだけ

動いてるとこ

ソース

public class StopWatch extends AppCompatActivity {
    Button btStart;
    Button btStop;
    TextView disp;
    Handler handler = new Handler();
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            count++;
            disp.setText(dataFormat.format(count*period));
            handler.postDelayed(this, period);
        }
    };
    int count, period;
    private SimpleDateFormat dataFormat =
            new SimpleDateFormat("mm:ss.S", Locale.US);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_stop_watch);

        btStart = findViewById(R.id.button);
        btStop = findViewById(R.id.button2);
        disp = findViewById(R.id.textView);

        count = 0;
        period = 100;

    }

    public void onClickStart(View v){
        handler.post(runnable);
    }

    public void onClickStop(View v){
        handler.removeCallbacks(runnable);
        disp.setText(dataFormat.format(0));
        count = 0;
    }

所感

処理の順序が全然わからんかったのがちょっと分かった。

参考

https://akira-watson.com/android/timertask.html

https://dev.classmethod.jp/smartphone/android/android-tas/

Timer・TimerTask使う

動いてるとこ

そーす

public class StopWatch extends AppCompatActivity {
    Button btStart;
    Button btStop;
    TextView disp;
    Handler handler = new Handler();
    int count;
    MyTimerTask timerTask = null;
    Timer mTimer = null;
    private SimpleDateFormat dataFormat = new SimpleDateFormat("mm:ss.S", Locale.US);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_stop_watch);

        btStart = findViewById(R.id.button);
        btStop = findViewById(R.id.button2);
        disp = findViewById(R.id.textView);

        count = 0;

    }

    public void onClickStart(View v) {
        if (mTimer == null) {
            timerTask = new MyTimerTask();
            count = 0;
            mTimer = new Timer(true);
            mTimer.schedule(timerTask, 100, 100);
        }
    }

    public void onClickStop(View v) {
        if (mTimer != null) {
            mTimer.cancel();
            mTimer = null;
            disp.setText(dataFormat.format(0));
        }
    }

    class MyTimerTask extends TimerTask {

        @Override
        public void run() {
            handler.post(new Runnable() {
                public void run() {

                    count++;
                    disp.setText(dataFormat.format(count * 100));
                }
            });
        }
    }
}

所感

スタートボタン押すとmTimerが空かどうかチェック。mTimerにTimerをnewする時にtrueでデーモンスレッドにする。mTimer.schedule(timerTask, delay, period)でスケジュールをセット。timerTaskの中身は、handlerでメインスレッドに投げる処理(1個目のrun)、カウントアップしてUIに表示させる処理(2個目のrun)、でこの2つをdelay, periodを100msの設定でセットしてるので、その間隔で2つの処理が実行される。この時本当は、scheduleではなく、scheduleAtFixedRateを使った方が良いみたい。

scheduleメソッド:前回のタスク実行後を基準にperiodミリ秒後が次のタイミング
scheduleAtFixedRateメソッド:初回のタスク実行時間を基準にperiodミリ秒 x n回後が次のタイミング

なので、scheduleだとタスク処理の時間分、次回タスク処理の開始が遅れるからかな?そうすると多分ちょっとずつ時間が遅れるんだろう。他にscheduleWithFixedDelayっていうのがあるみたい。

これ使った場合でも、Pauseした時にその時の値を保持しておいて、次回実行時にその値から始める、みたいにすれば一時停止ができるのかなぁ…なんとなく。

参考

https://techbooster.org/android/application/934/

https://blog.mumei-himazin.info/?p=474

https://qiita.com/opengl-8080/items/ee8e926cf75e4d6058a2

ScheduledExecutorService使う

動いてるとこ

ソース

public class StopWatch extends AppCompatActivity {
    Button btStart;
    Button btStop;
    Button btPause;
    TextView disp;
    Handler handler = new Handler();
    int count;
    MyTimerTask timerTask = null;
    ScheduledExecutorService scheduler = null;
    ScheduledFuture<?> sf = null;
    private SimpleDateFormat dataFormat = new SimpleDateFormat("mm:ss.S", Locale.US);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_stop_watch);

        btStart = findViewById(R.id.button);
        btStop = findViewById(R.id.button2);
        btPause = findViewById(R.id.button3);
        disp = findViewById(R.id.textView);

        count = 0;
    }

    public void onClickStart(View v) {
        if (scheduler == null) {
            scheduler = Executors.newScheduledThreadPool(1);
            timerTask = new MyTimerTask();
            sf = scheduler.scheduleAtFixedRate(timerTask, 100, 100, MILLISECONDS);
            count = 0;
        }
    }

    public void onClickPause(View v) {

        if (sf == null) {
            return;
        }

        if (sf.isCancelled()) {
            sf = scheduler.scheduleAtFixedRate(timerTask, 100, 100, MILLISECONDS);
            btPause.setText("Pause");
        } else {
            sf.cancel(true);
            btPause.setText("Resume");
        }
    }

    public void onClickStop(View v) {
        if (scheduler != null) {
            scheduler.shutdown();
            scheduler = null;
            sf = null;
            disp.setText(dataFormat.format(0));
        }
    }

    class MyTimerTask implements Runnable {

        @Override
        public void run() {
            handler.post(new Runnable() {
                public void run() {
                    count++;
                    disp.setText(dataFormat.format(count * 100));
                }
            });
        }
    }
}

所感

使い方は大体Timer・TimerTaskと似てるみたい。初期化する時にスレッド数を指定するのと、scheduleAtFixedRateの引数が、RunnableなのでMyTimerTaskをextends TimerTaskからimplements Runnableに変更、あとTimeUnitが必要なのと、止める時shutdownになるのとかが違う。shutdownするとやっぱり破棄されるのかな?

ScheduledFuture<?>が肝で、そういえばこの後ろの<?>ってなんだろう、scheduleAtFixedRateの戻り値がScheduledFuture<?>なので変数sfを用意して受けてあげる。そんでcancel(boolean)でスケジュールを保留状態にできる。保留状態の時、sf.isCancelledがtrueになるので、それで処理を分けてあげると。難しいのう。

参考

http://www.02.246.ne.jp/~torutk/javahow2/timer.html#doc1_id147

https://developer.android.com/reference/java/util/concurrent/ScheduledExecutorService

https://docs.oracle.com/javase/jp/8/docs/api/java/util/concurrent/Future.html

https://oshiete.goo.ne.jp/qa/111300.html

うぬぬ

これを1から自分で作れと言われた場合、絶対できないと思う。まだなんとなーく、ふわーっとした理解だなぁ。

補記:activity_stop_watch.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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=".StopWatch">

    <TextView
        android:id="@+id/textView"
        android:layout_width="0dp"
        android:layout_height="166dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:text="00:00.00"
        app:autoSizeTextType="uniform"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="12dp"
        android:layout_marginBottom="8dp"
        android:onClick="onClickStart"
        android:text="Start"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView"
        app:layout_constraintVertical_bias="0.141" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="12dp"
        android:layout_marginEnd="8dp"
        android:layout_marginBottom="8dp"
        android:onClick="onClickStop"
        android:text="Stop"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView"
        app:layout_constraintVertical_bias="0.141" />

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginBottom="8dp"
        android:onClick="onClickPause"
        android:text="Pause"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/button2"
        app:layout_constraintStart_toEndOf="@+id/button"
        app:layout_constraintTop_toBottomOf="@+id/textView"
        app:layout_constraintVertical_bias="0.153" />
</android.support.constraint.ConstraintLayout>

 

カテゴリー: のーと タグ: , , , パーマリンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です