音声ファイルの再生
それでは、音声ファイルの再生処理を記述していきましょう。
メディアプレイヤーの準備
Androidで音声ファイルを再生するにはMediaPlayerクラスを使用します。以下のソースコードを記述してください。
public class MediaControlActivity extends AppCompatActivity { private MediaPlayer _player; // (1) private Button _btPlay; // (2) private Button _btBack; // (2) private Button _btForward; // (2) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // (3) setContentView(R.layout.activity_media_control); // (3) _btPlay = (Button) findViewById(R.id.btPlay); // (4) _btBack = (Button) findViewById(R.id.btBack); // (4) _btForward = (Button) findViewById(R.id.btForward); // (4) _player = new MediaPlayer(); // (5) String mediaFileUriStr = "android.resource://" + getPackageName() + "/" + R.raw.mountain_stream; // (6) Uri mediaFileUri = Uri.parse(mediaFileUriStr); // (7) try { _player.setDataSource(SoundStartActivity.this, mediaFileUri); // (8) _player.setOnPreparedListener(new PlayerPreparedListener()); // (9) _player.setOnCompletionListener(new PlayerCompletionListener()); // (10) _player.prepareAsync(); // (11) } catch (IOException e) { } } }
上記(3)はあらかじめ記述されているコードです。
現在押せないようになっているボタンですが、後に押せるように変更します。そのためにフィールドとして保持し、onCreate()内で中身を取得しておきます。それが(2)と(4)です。
同様に、MediaPlayerオブジェクトに関しても、他のメソッド内で操作するので、フィールドで宣言し、onCreate()内でnewします。それが(1)と(5)です。
このMediaPlayerで再生する音声ファイルを指定するのがsetDataSource()メソッドです。その際、第1引数としてコンテキストを、第2引数として音声ファイルのUriオブジェクトを指定します。それが(8)です。
なお、事前に第2引数で使用するUriオブジェクトを生成しています。それが(6)と(7)です。(6)でURI文字列を生成しています。アプリ内のリソース音声ファイルを表すURI文字列は
android.resource://アプリのルートパッケージ/リソースファイルのR値
で表します。ここでは、アプリのルートパッケージである「com.websarva.wings.android.mediasample」を直接記述せずにgetPackageName()で取得しています。
(7)では、こうして生成されたURI文字列からUriクラスのparse()メソッドを使用してUriオブジェクトを生成しています。
音声ファイルの指定ができたら、このファイルを読み込んで再生準備をさせますが、非同期で準備させた方が安全です。それが(11)で、prepareAsync()メソッドを使います。その際、準備が完了したときの処理を行うリスナクラスの設定が必要です。それが(9)です。リスナクラスは後で記述します。
同様に、音声ファイルの再生が終了した際に行う処理のリスナクラスを設定しているのが(10)です。こちらも後で記述します。
[Note]なぜURI指定か?
音声ファイルを指定する際、直接R値を指定する方法もあります。
ただ、MediaPlayerクラスは音声ファイルだけでなく、インターネットのストリーミングを再生することもできます。その場合は、URI文字列としてURLを記述します。
このように、さまざまな音声メディアに対応できるように、URI指定となっているのです。
また、「再生準備」や「準備ができたときのリスナクラス設定」などの回りくどい方法もこういったストリーミングに対応するためです。
リスナクラスの記述
では、リスナクラスを記述しましょう。MediaControlActivityに以下のメンバクラスを追記してください。
private class PlayerPreparedListener implements MediaPlayer.OnPreparedListener { @Override public void onPrepared(MediaPlayer mp) { _btPlay.setEnabled(true); // (1) _btBack.setEnabled(true); // (1) _btForward.setEnabled(true); // (1) } } private class PlayerCompletionListener implements MediaPlayer.OnCompletionListener { @Override public void onCompletion(MediaPlayer mp) { _btPlay.setText(R.string.bt_play_play); // (2) } }
再生準備が完了した時のリスナクラスはOnPreparedListenerインターフェースを、再生が終了したときのリスナクラスはOnCompletionListenerインターフェースを実装します。いずれも、MediaPlayerのメンバインターフェースです。
ここでは、準備が整った時に押せなかったボタンを押せるように変更しています。それが(1)です。また、再生が終了したときには、ボタンの表記を「一時停止」から「再生」に戻すようにします。それが(2)です(後で出てきますが、再生開始と同時に表記を「一時停止」に変更します)。
この状態で、一度アプリを起動してみてください。先ほど押せなかったボタンがタップできるようになっているはずです。ただ、タップするとエラーでアプリが終了します。これは、タップ時の処理が記述されていないからです。次にそこを記述しましょう。
再生と破棄
まず、再生ボタンをタップした時にメディアファイルを再生させるよう記述していきます(他の2個のボタンは後で処理を記述します)。これは、ボタンのonClick属性で指定したメソッドonPlayButtonClick()に記述していきます。以下のソースコードを追記してください。
public void onPlayButtonClick(View view) { if(!_player.isPlaying()) { // (1) _player.start(); // (2) _btPlay.setText(R.string.bt_play_pause); // (3) } }
メディアの再生はstart()メソッドを使用します。それが(2)です。その後、ボタンの表記を「一時停止」に変更します。それが(3)です。ただし、これらは、すでに再生中の場合は行いません。そのために再生中かどうかの判定を行っているのが(1)です。MediaPlayerクラスのメソッドisPlaying()で再生中かどうかを確認できます。
ところで、MediaPlayerをアクティビティ中で使用した場合、アクティビティの終了と同時に確実にMediaPlayerオブジェクトを解放しておく必要があります。その処理をonDestroy()メソッドに記述します。
protected void onDestroy() { super.onDestroy(); // (1) if(_player.isPlaying()) { // (2) _player.stop(); // (3) } _player.release(); // (4) _player = null; // (5) }
(1)は親クラスのonDestroy()の呼び出しです。
MediaPlayerの解放は(4)と(5)です。release()メソッドで解放し、さらに、変数をnullにすることで確実に解放します。ただし、その前に、メディアが再生中なら停止する必要があります。その処理が(2)と(3)です。(2)で再生中かどうかを判定し、(3)で再生を停止します。停止メソッドはstop()です。
これで一通りのソースコードが記述できましたので、アプリを再起動して、再生ボタンをタップしてみてください。音声が流れます。
再生中はいくらボタンをタップしても変化ありませんが、再生が終了したらボタンの表記が変更され、もう一度再生できます。
また、再生途中でバックボタンをタップし、アクティビティを終了したら(ホームボタンでは終了しません)、再生が終了することが確認できます。