これを利用してカウントアップタイマー(ストップウォッチ)を作成します
Androidはシングル・スレッド モデルを基本としています
シングル・スレッド モデルとはアプリケーションが一度に 1 つの仕事しかできないようになっています
つまり例えば画面描写中にほかのプログラムで画面描写を行うことができないという感じです
これを利用してのカウントダウンタイマー作成を行いたいと思います
少々難しいことを書きましたがHandlerを使ってカウントアップタイマーを作ろうと思ったのは
カウントアップには前回Chronometerを使ったものを紹介しました
Chronometerを使ったカウントアップタイマー
これで簡単にstart/stop/clearが使用できますがこれでは1秒以下の表記ができないからです
(0.5秒とか)
そのためにストップウォッチのようなカウントアップを作成するためにHandlerの選択になりました
Handler sendMessageDelayed()を使う
まずはHandlerを拡張した独自クラスLoopEngineを作成します
その中にstart()メソッドとstop()メソッドとhandleMessageを作成します
class Loopengine
//一定時間後にupdateを呼ぶためのオブジェクト class LoopEngine extends Handler { private boolean isUpdate; public void start(){ this.isUpdate = true; handleMessage(new Message()); } public void stop(){ this.isUpdate = false; } @Override public void handleMessage(Message msg) { this.removeMessages(0);//既存のメッセージは削除 if(this.isUpdate){ MainActivity.this.update();//自信が発したメッセージを取得してupdateを実行 sendMessageDelayed(obtainMessage(0), 100);//100ミリ秒後にメッセージを出力 } } };まずはstart()を呼び出すとhandleMessageが呼び出されます
HandleMessageではsendMessageDelayedで一定時間ウェイトしてメッセージを出力しています
つまり (1)start()メソッド実行
(2)HandleMessage呼び出す
(3)MainActivity.this.update()を実行
(4)sendMessageDelayedにより一定時間待ってメッセージ発行
(5)自身が発したメッセージを受け取りsendMessageDelayedを実行
以下(3)〜(5)を繰り返し
この繰り返しはActivity内でその他の操作・動作にかかわらず行えるため
Handlerを使ったマルチスレッドが活きてきます
今回はsendMessageDelayed(obtainMessage(0), 100);としているので100ミリ秒ごとに
updateが呼ばれることになります
このupdateにタイマーを更新するプログラムを書いておけばストップウォッチが作成できます
カウントアップタイマー(ストップウォッチ)
startボタンとstopボタンを備えた0.1秒まで測定できるストップウォッチを作成しました
まずはmain.xmlの作成です
ボタン2つに(startとstop)テキストビューを5つ配置しました
(分・秒・1/10秒とそれぞれの区切り)
layout/main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" > <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="00" android:textSize="30sp"/> <TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=":" android:textSize="30sp"/> <TextView android:id="@+id/textView3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="00" android:textSize="30sp"/> <TextView android:id="@+id/textView4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="." android:textSize="30sp"/> <TextView android:id="@+id/textView5" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="0" android:textSize="30sp"/> </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" > <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="start" /> <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="stop" /> </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" > </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" > </LinearLayout> </LinearLayout>
なお文字が見やすいように文字サイズを30spにしてあります
次にMainActivity.javaです
こちらは先ほどのLoopEngineと各種ボタン動作
また、updateによるタイムの更新を作成しています
MainActivity.java
package blog.test; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; public class MainActivity extends Activity { TextView timer_m,timer_s,timer_ms; Button start,stop,restart; int minute,second,m_second; private LoopEngine loopEngine = new LoopEngine(); private long startDate; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); timer_m = (TextView)findViewById(R.id.textView1); timer_s = (TextView)findViewById(R.id.textView3); timer_ms = (TextView)findViewById(R.id.textView5); start =(Button)findViewById(R.id.button1); stop =(Button)findViewById(R.id.button2); start.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { startDate =System.currentTimeMillis(); loopEngine.start(); } }); stop.setOnClickListener(new OnClickListener(){ public void onClick(View v) { loopEngine.stop(); } }); } public void update(){ minute =(int)((((System.currentTimeMillis()-startDate))/1000)/60); second =(int)((((System.currentTimeMillis()-startDate))/1000)%60); m_second =(int)(((System.currentTimeMillis()-startDate)/10)%10); timer_m.setText(String.format("%1$02d",minute)); timer_s.setText(String.format("%1$02d",second)); timer_ms.setText(String.format("%1$01d",m_second)); } //一定時間後にupdateを呼ぶためのオブジェクト class LoopEngine extends Handler { private boolean isUpdate; public void start(){ this.isUpdate = true; handleMessage(new Message()); } public void stop(){ this.isUpdate = false; } @Override public void handleMessage(Message msg) { this.removeMessages(0);//既存のメッセージは削除 if(this.isUpdate){ MainActivity.this.update();//自信が発したメッセージを取得してupdateを実行 sendMessageDelayed(obtainMessage(0), 100);//100ミリ秒後にメッセージを出力 } } }; }
System.currentTimeMillis();では
現在の時刻をアンドロイドシステムからミリ秒で取得しています
startボタンを押すとstartDateに現在の時刻を記録
update内で再び現在の時刻を取得しstartDateを引いて経過時間を測定しています
またtimer_m.setText(String.format("%1$02d",minute));
ではminuteを2ケタ表示させ、1桁目に何もない時は“0”を表示させる設定にさせています
こちらを実行すると
startボタンでタイマーがスタートし、stopボタンで止まります
・・・え?動きがカクついてる・・?
それはupdateを呼び出すのが100ミリ秒ごとだからだと思います
ためしにsendMessageDelayed(obtainMessage(0), 1);とかにすると
だいぶスムーズになりますが負荷的にどうなんだろうww
スポンサードリンク
【タイマー カウントダウンの最新記事】