【发布时间】:2011-07-12 17:19:35
【问题描述】:
想知道应用程序关闭后如何播放下一首歌曲,就像播放整张 CD 或播放列表一样...
【问题讨论】:
-
“应用已关闭”是指根本不显示在任务管理器中,还是只显示在后台?
-
我想我的意思是当它在后台时。
标签: android media-player
想知道应用程序关闭后如何播放下一首歌曲,就像播放整张 CD 或播放列表一样...
【问题讨论】:
标签: android media-player
媒体播放器只播放一个音轨。 媒体播放器所做的是监听 onCompletion 事件并播放下一首曲目。
MediaPlayer 绑定到进程,而不是 Activity,因此只要进程运行,它就会一直播放。 Activity 可能会被暂停或销毁,但这不会影响 MediaPlayer 使用的内部线程。
我正在构建一个音频播放器来学习Android,你可以看到播放音频文件的服务here
关于第一条评论:该服务一直在后台运行,并在您“退出”应用程序后继续运行,因为服务和活动的生命周期不同。
为了播放下一首曲目,服务会在 MediaPlayer 上注册一个回调,以便在音频流完成时通知服务。当音频完成时,该服务通过调用 MediaPlayer.release() 清理 MediaPlayer 使用的资源,然后创建一个新的媒体播放器,其中包含要播放的下一个音轨,并注册自己以在该音轨时再次收到通知完成,无穷无尽:)。
MediaPlayer 类不理解播放列表,因此该服务负责在前一曲目完成后播放曲目。
在我创建的AudioPlayer 服务中,一个活动在AudioPlayer 中对曲目进行排队,AudioPlayer 负责按顺序播放它们。
我希望它清楚,如果你有时间,请检查我上面放的 AudioPlayer 服务的代码。这不是纯粹的美丽,但它确实发挥了作用。
【讨论】:
您可以创建一个服务以在您的应用退出或暂停后继续播放 MediaPlayer。要让 MediaPlayer 播放连续曲目,您可以注册一个 onCompletionListener 来决定接下来播放哪个曲目。这是一个执行此操作的简单示例服务:
package edu.gvsu.cis.muzak;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.net.Uri;
import android.os.IBinder;
import android.util.Log;
public class MuzakService extends Service {
private static final String DEBUG_TAG = "MuzakService";
private MediaPlayer mp;
private String[] tracks = {
"http://freedownloads.last.fm/download/288181172/Nocturne.mp3",
"http://freedownloads.last.fm/download/367924875/Behemoths%2BSternentanz.mp3",
"http://freedownloads.last.fm/download/185193341/Snowflake%2BImpromptu.mp3",
"http://freedownloads.last.fm/download/305596593/Prel%25C3%25BAdio.mp3",
"http://freedownloads.last.fm/download/142005075/Piano%2BSonata%2B22%2B-%2Bmovement%2B2%2B%2528Beethoven%2529.mp3",
"http://freedownloads.last.fm/download/106179902/Piano%2BSonata%2B%25231%2B-%2Bmovement%2B%25234%2B%2528Brahms%2529.mp3",
};
private int currentTrack = 0;
@Override
public void onCreate() {
super.onCreate();
Log.d(DEBUG_TAG, "In onCreate.");
try {
Uri file = Uri.parse(tracks[this.currentTrack]);
mp = new MediaPlayer();
mp.setDataSource(this, file);
mp.prepare();
mp.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
currentTrack = (currentTrack + 1) % tracks.length;
Uri nextTrack = Uri.parse(tracks[currentTrack]);
try {
mp.setDataSource(MuzakService.this,nextTrack);
mp.prepare();
mp.start();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
} catch (Exception e) {
Log.e(DEBUG_TAG, "Player failed", e);
}
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Log.d(DEBUG_TAG, "In onDestroy.");
if(mp != null) {
mp.stop();
}
}
@Override
public int onStartCommand(Intent intent,int flags, int startId) {
super.onStart(intent, startId);
Log.d(DEBUG_TAG, "In onStart.");
mp.start();
return Service.START_STICKY_COMPATIBILITY;
}
@Override
public IBinder onBind(Intent intent) {
Log.d(DEBUG_TAG, "In onBind with intent=" + intent.getAction());
return null;
}
}
您可以按如下方式在 Activity 中启动此服务:
Intent serv = new Intent(this,MuzakService.class);
startService(serv);
然后像这样停止它:
Intent serv = new Intent(this,MuzakService.class);
stopService(serv);
【讨论】:
请注意,服务也在前台运行。
请查看官方文档。它用示例代码解释。 使用带有 MediaPlayer 的服务: http://developer.android.com/guide/topics/media/mediaplayer.html#mpandservices
作为前台服务运行
服务通常用于执行后台任务
但是考虑一下正在播放音乐的服务的情况。显然,这是用户主动了解的服务,任何中断都会严重影响体验。此外,它是用户可能希望在执行期间与之交互的服务。在这种情况下,服务应该作为“前台服务”运行。前台服务在系统中具有更高级别的重要性——系统几乎不会杀死该服务,因为它对用户具有直接的重要性。在前台运行时,服务还必须提供状态栏通知,以确保用户知道正在运行的服务并允许他们打开可以与服务交互的活动。
为了将你的服务变成前台服务,你必须为状态栏创建一个通知并从服务中调用 startForeground()
【讨论】:
mediap 播放器应该从服务运行,这里我已经将歌曲的数组列表从活动传递到服务,所有歌曲都是通过读取数组列表来运行的
public class MyService extends Service implements OnCompletionListener,
MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener{
Context context;
private static final String ACTION_PLAY = "PLAY";
private static final String TAG = "SONG SERVICE";
MediaPlayer mediaPlayer;
private int currentTrack = 0;
ArrayList<String> list;
public MyService() {
context=getBaseContext();
}
@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
list = (ArrayList<String>)intent.getSerializableExtra("arraylist");
int count=0;
Log.d(TAG, "total count:"+list.size());
//playing song one by one
for (String string : list) {
//play(string);
count++;
Log.d(TAG, "count:"+list);
}
play(currentTrack);
Log.d(TAG, "count:"+count);
if(count==list.size()){
//stopSelf();
Log.d(TAG, "stoping service");
//mediaPlayer.setOnCompletionListener(this);
}else{
Log.d(TAG, "not stoping service");
}
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
Log.d(TAG, "oncommat");
}
return START_STICKY;
}
@Override
public void onCreate() {
Toast.makeText(this, "Service was Created", Toast.LENGTH_LONG).show();
}
@Override
public void onStart(Intent intent, int startId) {
// Perform your long running operations here.
Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
}
@Override
public void onDestroy() {
Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show();
Log.d("service", "destroyed");
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.release();
}
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
// TODO Auto-generated method stub
return false;
}
@Override
public void onPrepared(MediaPlayer mp) {
// TODO Auto-generated method stub
}
private void play(int id) {
if(mediaPlayer!=null && mediaPlayer.isPlaying()){
Log.d("*****begin*****", "playing");
stopPlaying();
Log.d("*****begin*****", "stoping");
} else{
Log.d("*****begin*****", "nothing");
}
Log.d("*****play count*****", "="+currentTrack);
Log.i("******playing", list.get(currentTrack));
Uri myUri1 = Uri.parse(list.get(id));
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
//mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
mediaPlayer.setOnPreparedListener(this);
//mediaPlayer.setOnCompletionListener(this);
mediaPlayer.setOnErrorListener(this);
try {
mediaPlayer.setDataSource(context, myUri1);
Log.i("******playing", myUri1.getPath());
} catch (IllegalArgumentException e) {
Toast.makeText(context, "You might not set the URI correctly!", Toast.LENGTH_LONG).show();
} catch (SecurityException e) {
Toast.makeText(context, "You might not set the URI correctly!", Toast.LENGTH_LONG).show();
} catch (IllegalStateException e) {
Toast.makeText(context, "You might not set the URI correctly!", Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
}
try {
mediaPlayer.prepare();
} catch (IllegalStateException e) {
Toast.makeText(context, "You might not set the URI correctly!", Toast.LENGTH_LONG).show();
} catch (IOException e) {
Toast.makeText(context, "You might not set the URI correctly!", Toast.LENGTH_LONG).show();
}
mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
currentTrack=currentTrack+1;
play(currentTrack);
/* currentTrack = (currentTrack + 1) % list.size();
Uri nextTrack=Uri.parse(list.get(currentTrack));
try {
mediaPlayer.setDataSource(context,nextTrack);
mediaPlayer.prepare();
// mediaPlayer.start();
} catch (Exception e) {
e.printStackTrace();
}*/
}
});
mediaPlayer.start();
}
private void stopPlaying() {
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
}
@Override
public void onCompletion(MediaPlayer mp) {
// TODO Auto-generated method stub
}
【讨论】:
答案是 Android 中的服务,如下所述:http://developer.android.com/guide/topics/fundamentals.html as
您将创建一个服务,当您从应用收到播放命令时,您的应用将向后台服务发送消息以播放音乐。服务不会在前台运行,因此即使您将屏幕置于睡眠状态,它也会播放音乐。
【讨论】: