前回の訂正とおわび
今回は、「オーディオリモコン」を駆使して音楽プレイヤーを作成するという前回記事「Androidのウィジェットにノーティフィケーションするには」の続きです。
最初に謝っておかなければならないのですが、筆者は「RemoteViews」を使用するすべての個所で「RemoteContorlClientを駆使したオーディオリモコンの機能が使用できる」と勘違いしていましたが、実際にはロック画面でのみ使用できるものでした。きちんと下調べができておらず、申しわけありませんでした。
しかし、「Notification」クラスからマルチメディアを操作できるようになるのは便利なので、引き続きNotificationの扱い方や、ロック画面でのオーディオリモコンの使い方に関しても解説していきます。
*** 一部省略されたコンテンツがあります。PC版でご覧ください。 ***
今回のサンプルアプリは以下からダウンロードできます。
今回のアプリは、「RandomMusicPlayer」というAndroid SDKに付属するサンプルを一部流用して、分かりやすく変更しています。関係のない部分を、ばっさり削除したり、後方互換のためのリフレクションなどを適切に修正しているため、ずいぶん分かりやすくなっているはずです。
まずは、MediaPlayerクラスの使い方から
オーディオリモコンや、Notificationからの「MediaPlayer」クラスの操作は、「ブロードキャスト」を飛ばしたり受け取ったりと、本来のMediaPlayerの制御とはかけ離れた処理を行わなければならないため、かなり複雑です。
また、MediaPlayerは“状態”を持つオブジェクトであり、この状態管理がまたかなり難しいため、まずはMediaPlayerの使い方にフォーカスして解説します。
状態遷移
以下はMediaPlayerの状態遷移図です。
これまでの連載で見てきた状態遷移図の中で最も複雑です。各状態で呼び出し可能なメソッドは上図の通りです。それ以外のメソッドを呼び出すと、例外が発生したり、内部的にエラーになったりします。
さらにMediaPlayerには、現在の状態を問い合わせるメソッドが提供されていません。つまり、MediaPlayerを使用する場合は、アプリがその状態を完全に把握しておかなければなりません。MediaPlayerを使用する際には、この状態管理が一番大変です。
とはいえ、その大変な状態管理の負荷を軽減する方法はないこともありません。
方法【1】1つのデータソースにつき、1つのMediaPlayerを割り当てる
これは、ゲームのサウンドエフェクトなどで有効な方法でしょう。状態管理を難しくしている要因の1つに、データソースの初期化と解放があります。これらが1度で済むのは、状態管理を簡単にするという点において大きなメリットです。
ですが、例えば、ミサイルが3連射できるとか、爆発音を敵の数だけ重ねる必要があるといった場合には、同じデータソースを持つMediaPlayerを複数用意するなどの工夫が必要になるかもしれません。
方法【2】とにかく解放
「MediaPlyaer#reset()」メソッドを呼び出すと、状態が「Idle」に移行します。この「MediaPlayer#reset()」メソッドは「Preparing」「End」以外の状態で呼び出すことが可能です。次のデータを再生したい場合は、とにかく「Idle」に戻って、データの読み込みからやり直す、というのが簡単です。
注意しなければならないのは、データ読み込みは時間がかかるため、例えば「画面タップに合わせて音を鳴らしたい」というようなケースでは、この方法は不向きです。今回のサンプルの状態管理では、一部この方法を採用しています。
データを同期、非同期で読み込む
状態管理で特に気を付けなければならない点は、「Initialized」から「Prepared」に遷移する個所です。「MediaPlayer#setDataSource(String)」で指定したデータを実際に読み込むには、「MediaPlayer#prepare()」「MediaPlayer#prepareAsync()」の2通りの方法があり、それぞれ同期、非同期です。
同期は「MediaPlayer#reset()」を呼び出せない「Preparing」に移行しないので簡単ですが、UIスレッドをブロックしてユーザーを待たせてしまったり、最悪の場合は「ANR(Application Not Responding、アプリ無反応)」が発生してアプリが落ちてしまう可能性があります。
非同期の場合は、そのようなことはありませんが、ユーザーの操作が速過ぎて「Prepareing」中に再度「MediaPlayer#prepareAsync()」を呼び出してしまうということが起こりがちです。
「MediaPlayer#prepaer()」「MediaPlayer#prepareAsync()」の使い方については、後ほどコードを交えて解説します。
次ページ以降、サンプルコードを交えて初期化から終了までを解説します。
Copyright © ITmedia, Inc. All Rights Reserved.