前回の記事を応用してカウント読み上げタイマーを作成してみよう。
アプリの画面構成は以下のようになる。

startボタンを押すとカウント読み上げを開始する。
pauseボタンを押すとカウントを一時停止する。
resetボタンを押すとカウント値をリセットする。
この画面のレイアウトxmlは以下のようになる。
layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<Button android:text="Start"
android:id="@+id/btnStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</Button>
<Button android:text="Pause"
android:id="@+id/btnPause"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</Button>
<Button android:text="Reset"
android:id="@+id/btnReset"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</Button>
</LinearLayout>
次に、カウント処理を別クラスにまとめることにした。ソースは以下のようになる。
Counter.java
package com.lesson.tts;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
* カウントアップクラス
* 1秒ごとにイベントが呼ばれる
*/
public class Counter {
private final ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
private ScheduledFuture<?> future = null;
private int count = 0;
public interface OnCountListener{
void onCount( int count );
}
private OnCountListener listener;
public void setOnCountListener(OnCountListener l){
this.listener = l;
}
private final Runnable task = new Runnable() {
@Override
public void run() {
// 一秒ごとに呼び出される。
if( listener != null ){
listener.onCount(count);
}
count++;
}
};
/**
* スタート
*/
public void start(){
if( future == null){
future = ses.scheduleAtFixedRate(task, 0, 1000, TimeUnit.MILLISECONDS);
}
}
/**
* 停止
*/
public void pause(){
if( future != null ){
future.cancel(true);
future = null;
}
}
/**
* カウントリセット
*/
public void reset(){
count = 0;
}
}
ScheduledExecutorServiceを使い、等間隔で定期的な処理を行うようにしている。
このクラスにイベントリスナをセットすれば、カウントされたタイミングでイベントを受けることができる。
最後に、MainActivityを示す。
MainActivity.java
package com.lesson.tts;
import java.util.concurrent.TimeUnit;
import android.app.Activity;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.OnInitListener;
import android.view.View;
import android.view.View.OnClickListener;
import com.lesson.tts.Counter.OnCountListener;
public class MainActivity extends Activity {
private TextToSpeech tts;
private final Counter counter = new Counter();
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// カウントイベント時処理
counter.setOnCountListener(new OnCountListener() {
@Override
public void onCount(int count) {
tts.speak("" + count, TextToSpeech.QUEUE_FLUSH, null);
}
});
// TextToSpeech生成
tts = new TextToSpeech(this,new OnInitListener() {
@Override
public void onInit(int status) {
// TODO Auto-generated method stub
}
});
// カウント開始
findViewById(R.id.btnStart).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
counter.start();
}
});
// 一時停止
findViewById(R.id.btnPause).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
counter.pause();
}
});
// カウントリセット
findViewById(R.id.btnReset).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
counter.reset();
}
});
}
@Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
counter.pause();
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
tts.shutdown();
}
}
カウントアップ処理は外にまとめたので非常にシンプルなコードになっている。
MainActivityでやることは、カウントイベントのタイミングでSpeechToTextにカウント値を読み上げさせるだけである。
後は、アプリのライフサイクルイベントにあわせてカウンターの停止やSpeechToTextのシャットダウンを行う。
以上で簡単ながらカウント読み上げタイマーを作成することができた。
今回はカウントアップしかできないが、応用すればカウントダウンタイマーにしたりできるだろう。
※注)MainActivity側に書いてあるカウントイベント処理内(29-31行目)でUI要素を操作することはできない。
このイベントはUIスレッドとは別のスレッドから起動されるからである。このイベント内でUI要素を操作したいときはHandlerを使う必要がある。その場合は、例えば以下のようなソースになる。
handler.post(new Runnable() {
@Override
public void run() {
((TextView)findViewById(R.id.txtInfo)).setText("" + count);
}
});