【Android】カウント読み上げタイマーの作成

投稿者: | 2011年11月28日

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

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);
                    }
                });

コメントを残す

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