ケータイJavaのいろは 第三回 クラスTimerを使う


IDGジャパン JavaWorld 2001年8月号 に掲載された記事の原文を公開します。 編集の手がかなり加えられて掲載されたため、 雑誌に掲載されたものとは異なる部分があります (無断転載禁止)。

キッチンタイマー / 音楽を演奏する / コラム / 終わりに / 戻る / トップページ


キッチンタイマー

ではまずはタイマーの練習としてキッチンタイマーを作ってみましょう。 やはり時間になったら音楽を演奏してもらいたいので、音の演奏も扱います。
 

KitchenTimer.java

画面構成は図 1 のとおりです。 時間を入力して「開始」ボタンを押すと、しばらく待ちます。 指定した時間が経過すると音楽が演奏され、 図 2 の表示をして時間が来たことを知らせます。
 
このソースファイルが KitchenTimer.java (リスト 1) になります。
 
(図1 KitchenTimer.java の実行結果 (初期表示)) (図2 KitchenTimer.java の実行結果 (時間経過後))
 

ワンショットタイマー

 
i モード対応 Java プロファイルではリアルタイム処理などの実現のために、 タイマークラスが用意されています。タイマーは一定時間間隔で 定期的に処理を実行させたり (インターバルタイマー)、 一定時間経過後に処理を実行させる (ワンショットタイマー) ことができます。 リスト 1 ではワンショットタイマーを使っています。 Thread を使って自分で同様の処理を実装してもかまいませんが、 i アプリには容量に 10KB までの制限がありますから、 コード量が減らせて使いやすいタイマークラスを使うと良いと思います。
 
タイマークラスは com.nttdocomo.util.Timer クラスです。 Java2 Standard Edition の java.util.Timer クラスとは 名前や使用目的は同じですが、 別のクラスで使用方法が違いますので注意が必要です。 このタイマーはイベントの一種で、Timer クラスにリスナーを 登録する形になります。
 
Timer クラスをワンショットタイマーとして使う場合の使用方法は 以下のとおりです。まず、準備段階として Timer オブジェクトを生成し、 setListener(TimerListener listener) メソッドでリスナー (TimerListener インターフェースを実装したクラスのオブジェクト) を登録します。次に、setTime(int time) メソッドで何ミリ秒後に タイマーイベントを発生させるかを設定します。 リスト 1 では componentAction(Component source,int type,int param) メソッド (リスト 1 の 85 行目) のボタンが押された時の処理として 書かれています。
 
そして、start() メソッドでタイマーを開始します。 指定時間が経過するとリスナーの timerExpired(Timer source) メソッド (リスト 1 の 69 行目) が呼ばれます。 引数には ワンショットタイマーとして使った Timer オブジェクトが渡されます。
 
タイマーを使い終わったら dispose() メソッドで破棄して 後片付けを行います。リスト 1 のようにまだタイマーが 動作している可能性がある場合は stop() メソッドで停止させておくと 良いです (リスト 1 の 109, 110 行目)。
 

音の演奏

 
i モード対応 Java プロファイルでは i メロディ形式の音声ファイル、 つまり着メロの演奏が出来ます。
 
i メロディを読み込む方法は画像を読み込む場合と同様です。 MediaManager クラスのクラスメソッド getSound(String location) に i メロディファイルの置き場所を指定して MediaSound オブジェクトを取得します。 MediaSound インターフェースは読み込まれた音楽を表すクラスです。 使用前に use() メソッド (リスト 1 の loadSound(String file) メソッド)、 使用後に unuse(), dispose() メソッド (リスト 1 の 111, 112 行目) を 呼ぶ必要がある点も同じです。
 
音を演奏するには AudioPresenter クラスを使用します。 AudioPresenter オブジェクトはそのクラスの getAudioPresenter() クラスメソッドで取得し、 setSound(MediaSound sound) メソッドで音を設定します。 そして、play() メソッドで演奏します。 AudioPresenter クラスは UI コンポーネントの VisualPresenter クラスと 名前は似ていますが、使用方法は違うので注意が必要です。 VisualPresenter クラスは UI コンポーネントですが、 AudioPresenter クラスは UI コンポーネントではありません。
 
なお、エミュレーターでは .mid (スタンダート MIDI ファイル) が、 実際の携帯電話では .mld (i メロディファイル) が読み込めるファイルと なっているため、注意が必要です。 MIDI ファイルは市販のツールなどで、iメロディファイルは フリーウェアなど (脚注:KoNDoH さんの smdEd (http://tech.millto.net/~pngnews/kndh/Page/smded.html) や NAKA さんの MLD Creator 16 (http://i503.sourceforge.net/) などがあります) で作成し、 テスト時と公開時でファイルを使い分ける必要があります。
 
また、実際の携帯電話では PCM 音源も使える機種がありますが、 対応フォーマットは機種依存で PCM 音源が全く扱えない機種もあるので、 全機種共通で動く i アプリを作りたいのであれば PCM 音源は使えません。
 

ダイアログ

 
リスト 1 では指定時間が経過した時にダイアログを表示しています (図 2)。 ダイアログは、文章を表示して警告や情報をユーザーに示したり、 ユーザーに決定を促がす時に使用します。
 
ダイアログの表示は Dialog クラスを使います。 Dialog クラスは Frame クラスのサブクラスのため、 Display クラスの setCurrent(Frame frame) メソッドで 表示できるように見えますが、そのような使い方はできません。
 
まず、コンストラクタ Dialog(int type,String title) の 引数 type にダイアログの種類を Dialog クラスの定数で、 title にタイトル文字列を指定します。 次に、setText(String msg) メソッドで表示させたい文章を設定します。 表示開始は show() メソッドです。 ユーザーがダイアログを閉じるまで show() メソッドは待ちます。
 
今回は情報ダイアログ (DIALOG_INFO) として使用しましたが、 ユーザーに「はい」「いいえ」の選択を求める (DIALOG_YESNO) ことも 出来ます。その場合、show() メソッドの返り値で選択結果を判断します。 選択結果は BUTTON_YES など Dialog クラスの定数になっています。

音楽を演奏する

MelodyPlayer.java

もう一つ、タイマーと音を扱うサンプルを用います。 「ドレミンドレミンソミレドレミレ」などカタカナで簡単な音符を表記して、 携帯電話に演奏させるプログラムです。 画面構成は図 3, 4 のとおりです。 画面中央にカタカナで簡単な音符を入力し、 「演奏」ボタンを押すと入れたとおりに音が演奏されていきます。 演奏中は画面下の音符の絵がぱらぱらと動きます。
 
このソースファイルが MelodyPlayer.java (リスト 2)、 使用する画像が図 5, 6 になります。
 
(図3 MelodyPlayer.java の実行結果) (図4 MelodyPlayer.java の実行結果)
 
(図5 title.gif) (図6 animation.gif)
 

インターバルタイマー

 
今度は Timer クラスをインターバルタイマーとして使いました。 音を順番に演奏するために一定時間間隔で音符を 読み取る処理を行うためです。
 
Timer クラスをインターバルタイマーとして使う場合、 使用方法はワンショットタイマーの場合と似ています。 Timer オブジェクトの生成、リスナーの設定は全く同じです。 次に、setRepeat(boolean b) メソッドの引数に true を指定することで インターバルタイマーとして使用することを支持し、 setTime(int time) メソッドで何ミリ秒間隔で タイマーイベントを発生させるかを設定します。 リスト 2 では start() メソッド (リスト 2 の 106〜110 行目) 中に この処理を行っています。
 
あとはワンショットタイマーの場合と同じです。 start() メソッドでタイマーを開始すると、 指定時間間隔ごとにリスナーの timerExpired(Timer source) メソッド (リスト 2 の 115 行目) が呼ばれます。 タイマーを使い終わったら stop() メソッド、 dispose() メソッドで後片付けをする点も同じです (リスト 2 の 184, 185 行目)。
 
リスト 2 では MelodyPlayer オブジェクトをリスナーとし、 1000ms ごとに定期処理しています。
 

音の演奏時の注意

 
音は演奏前にそれまでの演奏を停止させています (136 行目)。 これは音を再生中に setSound(MediaSound sound) メソッドを 設定することは出来ない (例外が発生する) ためです。
 
また、N503i (NEC 製) の場合、AudioPresenter クラスの getAudioPresenter() メソッドで AudioPresenter オブジェクトを 取得後すぐに stop() メソッドを呼び出すと UIException 例外が投げられます。 そのため、61 行目で AudioPresenter オブジェクトを取得後、 すぐに仮に音の設定を行っています。
 
リスト 2 の loadSound(String file) メソッドと loadImage(String file) メソッドを見比べてみるとわかりますように、 画像と音の読み込みは非常に似ています。 これは MediaSound インターフェース、 MediaImage インターフェースとも同じ MediaResource インターフェースを継承しているためです。 この点を利用して、これら読み込んだリソースを Vector オブジェクトの変数 media に格納して、 プログラム終了時の exit() メソッド (リスト 2 の 186〜191 行目) で 後片付けの処理を一括して行いました。
 

VisualPresenter

 
演奏中に画面下の音符の絵を動かすために VisualPresenter クラスを使っています。繰り返しになりますが、 VisualPresenter クラスは UI コンポーネントで、 AudioPresenter クラスとは使い方が異なります。
 
VisualPresenter クラスはアニメーション GIF (図 6) などの 動画像を再生する UI コンポーネントです。 setImage(MediaImage image) メソッドで動画像を設定し、 play() メソッドで再生開始、stop() メソッドで再生停止です。
 
なお、エミュレーターでは静止画として表示されてしまうので 注意してください。
 

メディアイベント

 
AudioPresenter クラスや VisualPresenter クラスはメディアの 再生・中断・終了についてイベントを投げます。 リスト 2 ではアニメーションの再生の制御のために AudioPresenter オブジェクトのメディアイベントを受け取っています。
 
使い方は他のイベントと同様にリスナーを使います。 メディアイベントを受け取るには AudioPresenter オブジェクトに setMediaListener(MediaListener listener) メソッドでリスナー (MediaListener インターフェースを実装したクラスのオブジェクト) を 登録します。 AudioPresenter オブジェクトの再生状態が変化するとイベントが発生し、 リスナーの mediaAction(MediaPresenter source,int type,int param) メソッド (リスト 2 の 154 行目) が呼ばれます。 引数の変数 source にはイベントが発生した AudioPresenter オブジェクトが、 type にはイベントの種類が AudioPresenter クラスの定数で、 param にはイベントに応じたパラメーター値が渡されます。 使い方は VisualPresenter クラスも同様です。
 

絵文字

 
i モード対応 Java プロファイルでは絵文字が使用できます。 絵文字の正体は外字です。絵文字の対応する S-JIS コード、 Unicode は「i モード対応 Java コンテンツ開発ガイド 〜詳細編〜」に 記載されていますので、これを参考にします。
 
リスト 2 の 44 行目ではラベルの「楽譜」の文字の前に音符が三つ 並んだ形の絵文字を使っています。 このように文字列中で \u の後ろに Unicode のコード番号を 16 進数 4 桁で書けば使うことが出来ます。
 

バックライト

 
F503i (富士通製) などでは消費電力を考慮して i アプリ起動時に バックライトを消すようになっています (脚注:携帯電話の設定で常に点灯にすることも可能ですが、 その場合は i アプリから制御できなくなってしまいます)。 しかし、バックライトが消されてしまうと画面が見づらくなるので、 ここではバックライトを付けることにします。
 
バックライトを付けるには PhoneSystem クラスを使います。 PhoneSystem クラスは携帯電話のネイティブリソースにアクセスする手段を 提供するクラスです。 標準で制御できるネイティブリソースはバックライトのみですが、 メーカーの拡張によってバイブレーションなどの制御も出来るように なるようです。
 
PhoneSystem クラスにはクラスメソッド setAttribute(int attr,int value) のみが用意されており、 引数の attr に制御するネイティブリソースの種類、 value に設定する値を渡します。 バックライト点灯なら「PhoneSystem.setAttribute(PhoneSystem.DEV_BACKLIGHT,PhoneSystem.ATTR_BACKLIGHT_ON);」、 消灯なら「PhoneSystem.setAttribute(PhoneSystem.DEV_BACKLIGHT,PhoneSystem.ATTR_BACKLIGHT_OFF);」 となります。

[コラム]

コラム:P503isの4月問題は?

 
4 月に開発した i アプリが P503i (松下通信工業製) で ダウンロードできない不具合がありましたが、 新機種の P503is ではどのようになっているのか気になる方もいるかと思います。 P503is では ADF の最終更新日の月の表記に「Apr」「Apl」のいずれでも ダウンロードできるようになっていますので、ご安心ください。
 

コラム:SO503iのセキュリティー問題

 
SO503i (ソニー製) でセキュリティー上の不具合が見つかり、 回収されることになりました。しかし、中には携帯電話の交換を 行わない人もいると思います。そのような方たちがセキュリティー問題に 合ってしまわないためにアプリケーション側で対処しておいたほうが 良いと思います。
 
そのセキュリティー問題とは i アプリをバージョンアップをした際に、 使用スクラッチパッドのサイズが増えていると他の i アプリの スクラッチパッドの読み書きが出来てしまう問題です。 スクラッチパッドについては今後解説することになるので詳細は その時にお話ししますが、スクラッチパッドを使う際に ADF に その使用サイズを記述することになります。 i アプリのバージョンが上がった際にこのサイズを増加させてしまうと、 この問題にぶつかります。そのため、スクラッチパッド使用サイズを 増やした際には携帯電話の「バージョンアップ機能」を使うのではなく 再ダウンロードするようにしてもらいましょう。

終わりに

今回はタイマーや音の演奏をサンプルを交えて解説しました。 次回からは低レベル API を扱っていこうと思います。

戻る