【Android】動画プレイヤーのコードを利用して音楽プレイヤーを作る
以前作成した動画プレイヤーのソースコードをほぼそのまま使って今度は音楽プレイヤーを作ってみました。
※動画プレイヤーについては以下の記事を参考
- 【Android】VideoViewを使って動画再生アプリを作る① -- ストレージへのアクセス権限を取得 --
- 【Android】VideoViewを使って動画再生アプリを作る② -- 内部ストレージのファイル検索 --
- 【Android】VideoViewを使って動画再生アプリを作る③ -- カスタムリストビュー --
- 【Android】VideoViewを使って動画再生アプリを作る④ -- 全画面で動画再生 --
- 【Android】VideoViewを使って動画再生アプリを作る -- 不具合修正、軽微な修正 --
概要
アプリケーションの特徴
アプリケーションの特徴は以下のとおりで、1-2は動画プレイヤーのコードほぼそのままです。
内部ストレージからmp3ファイルを検索してリスト表示する。
チェックボックスで複数選択し、選択アイテムを連続再生する。
再生中画面では音量調節を可能にする。
再生画面でどのファイルを再生中かわかるようにする。
再生中にホーム画面へ戻ってもアプリケーション実行中はバックグラウンドで再生し続ける。
再生中のイメージ
実装
いくつかこのアプリケーションで新たに対応した内容を記載します。
音量調節
レイアウト
音量調節はSeekBarを使って行います。
<SeekBar
android:id="@+id/seekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Mp3Activity.java
Activity側ではOnSeekBarChangeListenerを設定して、SeekBarのつまみを変更したイベントで音量調節を実行します。
SeekBar seekBar = findViewById(R.id.seekBar);
audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
int volume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
int max = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
seekBar.setMax(max);
seekBar.setProgress(volume);
seekBar.setOnSeekBarChangeListener(
new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, seekBar.getProgress(), 0);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
//
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
//
}
}
);
バックグラウンドサービスで音楽ファイルを再生する
音楽ファイルの再生を行うクラスが以下です。
BackgroundService.java
public class BackgroundService extends Service {
List<MediaPlayer> mediaPlayers;
List<String> paths;
List<String> names;
int index;
BackgroundService context;
@Override
public void onCreate() {
super.onCreate();
}
protected void sendBroadCast(int index) {
Intent broadcastIntent = new Intent();
broadcastIntent.putExtra("index", index);
broadcastIntent.setAction("UPDATE_ACTION");
getBaseContext().sendBroadcast(broadcastIntent);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
paths = intent.getStringArrayListExtra("paths");
index = 0;
names = new ArrayList<>();
for (String path : paths) {
names.add(new File(path).getName());
}
sendBroadCast(index);
mediaPlayers = new ArrayList<>();
setMediaPlayer(0);
return startId;
}
@Override
public void onDestroy() {
super.onDestroy();
for (MediaPlayer mediaPlayer : mediaPlayers) {
if (mediaPlayer != null) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.release();
mediaPlayer = null;
}
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
/**
* MediaPlayer
* @param i
*/
private void setMediaPlayer(final int i) {
try {
mediaPlayers.add(new MediaPlayer());
mediaPlayers.get(i).setDataSource(paths.get(index));
mediaPlayers.get(i).prepare();
} catch (Exception e) {
Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
}
mediaPlayers.get(i).setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.seekTo(0);
mediaPlayer.start();
}
});
mediaPlayers.get(i).setOnCompletionListener(new MediaPlayer.OnCompletionListener(){
@Override
public void onCompletion(MediaPlayer mp) {
if (++index > (paths.size() - 1)) {
index = 0;
}
sendBroadCast(index);
try {
mediaPlayers.get(i).release();
mediaPlayers.set(i, null);
mediaPlayers.add(new MediaPlayer());
setMediaPlayer(i + 1);
} catch (Exception e) {
Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
}
}
});
}
}
setMediaPlayerメソッドで音楽ファイルの再生、曲の切り替えを行います。
sendBroadCastメソッドは1曲が終わった時次の曲に切り替わったことを呼び出し元へ通知します。呼び出し側のActivityでこれを受け取る処理が必要です。
バックグラウンドサービスを呼び出す側
上記のバックグラウンドサービスを呼び出すActivity側の処理が以下です。
Activityの呼び出しと同じようにIntentをつかってバックグラウンドサービスを開始します。
Mp3Activity.java
Intent intent = new Intent(getApplication(), BackgroundService.class);
ArrayList<String> paths = getIntent().getStringArrayListExtra("paths");
intent.putStringArrayListExtra("paths", paths);
startService(intent);
updateReceiver = new UpdateReceiver();
intentFilter = new IntentFilter();
intentFilter.addAction("UPDATE_ACTION");
registerReceiver(updateReceiver, intentFilter);
updateReceiver.registerHandler(updateHandler);
〜
private Handler updateHandler = new Handler() {
@Override
public void handleMessage(Message message) {
Bundle bundle = message.getData();
final int index = (Integer) bundle.get("index");
// 曲が切り替わったときに画面を更新する処理
adapter.notifyDataSetChanged();
}
};
UpdateHandlerはバックグラウンドサービスのsendBroadcastによって呼び出され、曲が切り替わったことが通知されるので、画面の更新をここで行います。
サービスの登録
最後に作成したBackgroundServiceクラスをAndroidManifestへ登録します。
AndroidManifest.xml
<service android:name=".BackgroundService" />
アプリケーション
先に言ってしまうとすでにリリース済みで以下よりダウンロードできます。
https://play.google.com/store/apps/details?id=com.swapps.mp3playerソースコード
この記事はかなりざっくりな記事となっていますが、以下がソースコードとなっています。
https://github.com/s-watanabe-apps/mp3-player/releases/tag/1.3エラーについて
MediaPlayerで再生中に止まってしまう場合
android.media.MediaPlayerを使用してアプリ内リソースのサウンドを再生するとき、再生開始から数秒で以下エラーが発生して止まってしまう原因についてです。
W/MediaPlayer-JNI: MediaPlayer finalized without being released
事象が発生するソースコード
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MediaPlayer mediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.bgm);
mediaPlayer.setVolume(0.1f, 0.1f);
mediaPlayer.setLooping(true);
mediaPlayer.seekTo(0);
mediaPlayer.start();
}
原因と対応
原因はMediaPlayerのインスタンスをローカル変数で持っているためでした。メンバ変数にしてやればOKです。
MediaPlayer mediaPlayer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.bgm);
mediaPlayer.setVolume(0.1f, 0.1f);
mediaPlayer.setLooping(true);
mediaPlayer.seekTo(0);
mediaPlayer.start();
}
バックグラウンド再生中に止まってしまう(2021/06/15追記)
W/ActivityManager: Stopping service due to app idle:
u0a370 -1m3s891ms com.swapps.mp3player/.BackgroundService
D/NuPlayerDriver: stop(0xec980470)
Android Pie(API Level28)から、バックグラウンドサービスはサービスを実行している間、通知を出しておかなくてはいけなくなりました。通知を出していないと強制停止させられ上記のエラーとなります。
対応については修正量が少し多いのでプルリクエストを作っておきました。
https://github.com/s-watanabe-apps/mp3-player/pull/1
これで音楽を再生中は以下のように通知バーにアプリケーションが起動中であることが表示されます。
コメント
コメントを投稿