Simon的回答是正确的。我遇到了类似的问题,我的片段中有音乐播放器,我需要在单击按钮时返回到该UI。您的情况类似,但是您想控制回放而不是返回UI。以下是我为我的应用程序所做的。这会处理包括洗牌和重复功能在内的音频列表的回放。这也会在通知栏中显示媒体控件。
- 使用以下代码创建服务
MusicPlayerService
:
public class MediaPlayerService extends Service implements MediaPlayer.OnCompletionListener,
MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener, MediaPlayer.OnSeekCompleteListener,
MediaPlayer.OnInfoListener, MediaPlayer.OnBufferingUpdateListener,
AudioManager.OnAudioFocusChangeListener {
public static final String ACTION_PLAY = "pkg_name.ACTION_PLAY";
public static final String ACTION_PAUSE = "pkg_name.ACTION_PAUSE";
public static final String ACTION_PREVIOUS = "pkg_name.ACTION_PREVIOUS";
public static final String ACTION_NEXT = "pkg_name.ACTION_NEXT";
public static final String ACTION_STOP = "pkg_name.ACTION_STOP";
private MediaPlayer mediaPlayer;
private MediaSessionManager mediaSessionManager;
private MediaSessionCompat mediaSession;
private MediaControllerCompat.TransportControls transportControls;
private static final int NOTIFICATION_ID = 101;
private int resumePosition;
private final IBinder iBinder = new LocalBinder();
private ArrayList<PlayableTrack> audioList;
private int audioIndex = -1;
private boolean ongoingCall = false;
private PhoneStateListener phoneStateListener;
private TelephonyManager telephonyManager;
private Bitmap albumArtBitmap;
private boolean shuffle = false;
private boolean repeat = false;
private Random rand;
@Override
public IBinder onBind(Intent intent) {
return iBinder;
}
@Override
public void onCreate() {
super.onCreate();
callStateListener();
registerBecomingNoisyReceiver();
register_playNewAudio();
rand = new Random();
StorageUtil storage = new StorageUtil(getApplicationContext());
shuffle = storage.loadShuffleRepeat("Shuffle");
repeat = storage.loadShuffleRepeat("Repeat");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
StorageUtil storage = new StorageUtil(getApplicationContext());
audioList = storage.loadAudio();
audioIndex = storage.loadAudioIndex();
if (audioIndex != -1 && audioIndex < audioList.size()) {
activeAudio = audioList.get(audioIndex);
} else {
stopSelf();
}
} catch (NullPointerException e) {
stopSelf();
}
if (mediaSessionManager == null) {
try {
initMediaSession();
initMediaPlayer();
} catch (RemoteException e) {
e.printStackTrace();
stopSelf();
}
buildNotification(PlaybackStatus.PLAYING);
}
handleIncomingActions(intent);
return super.onStartCommand(intent, flags, startId);
}
@Override
public boolean onUnbind(Intent intent) {
mediaSession.release();
removeNotification();
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
if (mediaPlayer != null) {
stopMedia();
mediaPlayer.reset();
}
if (phoneStateListener != null) {
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
}
removeNotification();
unregisterReceiver(becomingNoisyReceiver);
unregisterReceiver(playNewAudio);
Picasso.get().cancelRequest(target);
}
public class LocalBinder extends Binder {
public MediaPlayerService getService() {
return MediaPlayerService.this;
}
}
@Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
}
@Override
public void onCompletion(MediaPlayer mp) {
stopMedia();
}
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
switch (what) {
case MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK:
Log.d("MediaPlayer Error", "MEDIA ERROR NOT VALID FOR PROGRESSIVE PLAYBACK " + extra);
break;
case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
Log.d("MediaPlayer Error", "MEDIA ERROR SERVER DIED " + extra);
break;
case MediaPlayer.MEDIA_ERROR_UNKNOWN:
Log.d("MediaPlayer Error", "MEDIA ERROR UNKNOWN " + extra);
break;
}
return false;
}
@Override
public void onPrepared(MediaPlayer mp) {
playMedia();
}
@Override
public void onAudioFocusChange(int focusState) {
switch (focusState) {
case AudioManager.AUDIOFOCUS_GAIN:
if (mediaPlayer == null) initMediaPlayer();
else if (!mediaPlayer.isPlaying()) mediaPlayer.start();
mediaPlayer.setVolume(1.0f, 1.0f);
break;
case AudioManager.AUDIOFOCUS_LOSS:
if (mediaPlayer.isPlaying()) mediaPlayer.stop();
mediaPlayer.reset();
mediaPlayer = null;
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
if (mediaPlayer.isPlaying()) mediaPlayer.pause();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
if (mediaPlayer.isPlaying()) mediaPlayer.setVolume(0.1f, 0.1f);
break;
}
}
private void initMediaPlayer() {
if (mediaPlayer == null)
mediaPlayer = new MediaPlayer();
mediaPlayer.setOnCompletionListener(this);
mediaPlayer.setOnErrorListener(this);
mediaPlayer.setOnPreparedListener(this);
mediaPlayer.setOnBufferingUpdateListener(this);
mediaPlayer.setOnSeekCompleteListener(this);
mediaPlayer.setOnInfoListener(this);
mediaPlayer.reset();
mediaPlayer.setAudioAttributes(new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build());
try {
mediaPlayer.setDataSource(activeAudio.getFileLocation());
} catch (IOException e) {
e.printStackTrace();
stopSelf();
}
mediaPlayer.prepareAsync();
}
public void playMedia() {
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
buildNotification(PlaybackStatus.PLAYING);
Intent intent = new Intent("PLAYBACK_STARTED");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
private void stopMedia() {
if (mediaPlayer == null) return;
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
}
public void pauseMedia() {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
resumePosition = mediaPlayer.getCurrentPosition();
}
buildNotification(PlaybackStatus.PAUSED);
Intent intent = new Intent("PLAYBACK_PAUSED");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
private void resumeMedia() {
if (!mediaPlayer.isPlaying()) {
mediaPlayer.seekTo(resumePosition);
mediaPlayer.start();
buildNotification(PlaybackStatus.PLAYING);
Intent intent = new Intent("PLAYBACK_STARTED");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}
private BroadcastReceiver becomingNoisyReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
pauseMedia();
buildNotification(PlaybackStatus.PAUSED);
}
};
private void registerBecomingNoisyReceiver() {
IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
registerReceiver(becomingNoisyReceiver, intentFilter);
}
private void callStateListener() {
telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
phoneStateListener = new PhoneStateListener() {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_OFFHOOK:
case TelephonyManager.CALL_STATE_RINGING:
if (mediaPlayer != null) {
pauseMedia();
ongoingCall = true;
}
break;
case TelephonyManager.CALL_STATE_IDLE:
if (mediaPlayer != null) {
if (ongoingCall) {
ongoingCall = false;
resumeMedia();
}
}
break;
}
}
};
telephonyManager.listen(phoneStateListener,
PhoneStateListener.LISTEN_CALL_STATE);
}
private void initMediaSession() throws RemoteException {
if (mediaSessionManager != null) return;
mediaSessionManager = (MediaSessionManager) getSystemService(Context.MEDIA_SESSION_SERVICE);
mediaSession = new MediaSessionCompat(getApplicationContext(), "AudioPlayer");
transportControls = mediaSession.getController().getTransportControls();
mediaSession.setActive(true);
mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
updateMetaData();
mediaSession.setCallback(new MediaSessionCompat.Callback() {
@Override
public void onPlay() {
super.onPlay();
resumeMedia();
}
@Override
public void onPause() {
super.onPause();
pauseMedia();
}
});
}
private void updateMetaData() {
fetchBitmapOfAlbum();
mediaSession.setMetadata(new MediaMetadataCompat.Builder()
.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, albumArtBitmap)
.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, "")
.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, activeAudio.getAlbumName())
.putString(MediaMetadataCompat.METADATA_KEY_TITLE, activeAudio.getTrackName())
.build());
}
private Target target = new Target() {
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
albumArtBitmap = bitmap;
}
@Override
public void onBitmapFailed(Exception e, Drawable errorDrawable) {
}
@Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
};
private void fetchBitmapOfAlbum() {
Picasso.get().load(activeAudio.getAlbumArt())
.placeholder(R.drawable.rotate_animation)
.error(R.drawable.ic_blank)
.into(target);
}
private void buildNotification(PlaybackStatus playbackStatus) {
int notificationAction = android.R.drawable.ic_media_pause;
PendingIntent play_pauseAction = null;
if (playbackStatus == PlaybackStatus.PLAYING) {
notificationAction = android.R.drawable.ic_media_pause;
play_pauseAction = playbackAction(1);
} else if (playbackStatus == PlaybackStatus.PAUSED) {
notificationAction = android.R.drawable.ic_media_play;
play_pauseAction = playbackAction(0);
}
fetchBitmapOfAlbum();
String channelId = "";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
channelId = "APP_MUSIC";
}
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, channelId)
.setShowWhen(false)
.setStyle(new androidx.media.app.NotificationCompat.MediaStyle()
.setMediaSession(mediaSession.getSessionToken())
.setShowActionsInCompactView(0, 1, 2))
.setColor(ContextCompat.getColor(this.getApplicationContext(), R.color.colorAccent))
.setLargeIcon(albumArtBitmap)
.setSmallIcon(R.drawable.ic_stat_notifications)
.setContentText(activeAudio.getTrackName())
.setTicker(activeAudio.getAlbumName() + "-" + activeAudio.getTrackName())
.setOngoing(true)
.setContentTitle(activeAudio.getAlbumName())
.setContentInfo(activeAudio.getTrackName())
.addAction(notificationAction, "pause", play_pauseAction)
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).notify(NOTIFICATION_ID, notificationBuilder.build());
}
private PendingIntent playbackAction(int actionNumber) {
Intent playbackAction = new Intent(this, MediaPlayerService.class);
switch (actionNumber) {
case 0:
playbackAction.setAction(ACTION_PLAY);
return PendingIntent.getService(this, actionNumber, playbackAction, 0);
case 1:
playbackAction.setAction(ACTION_PAUSE);
return PendingIntent.getService(this, actionNumber, playbackAction, 0);
default:
break;
}
return null;
}
private void removeNotification() {
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(NOTIFICATION_ID);
}
private void handleIncomingActions(Intent playbackAction) {
if (playbackAction == null || playbackAction.getAction() == null) return;
String actionString = playbackAction.getAction();
if (actionString.equalsIgnoreCase(ACTION_PLAY)) {
transportControls.play();
} else if (actionString.equalsIgnoreCase(ACTION_PAUSE)) {
transportControls.pause();
}
}
private BroadcastReceiver playNewAudio = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
audioIndex = new StorageUtil(getApplicationContext()).loadAudioIndex();
if (audioIndex != -1 && audioIndex < audioList.size()) {
activeAudio = audioList.get(audioIndex);
} else {
stopSelf();
}
stopMedia();
mediaPlayer.reset();
initMediaPlayer();
updateMetaData();
buildNotification(PlaybackStatus.PLAYING);
}
};
private void register_playNewAudio() {
IntentFilter filter = new IntentFilter(MainActivity.Broadcast_PLAY_NEW_AUDIO);
registerReceiver(playNewAudio, filter);
}
public boolean isPlaying(){
return mediaPlayer.isPlaying();
}
public void setShuffle(){
if(shuffle) shuffle=false;
else shuffle=true;
StorageUtil storage = new StorageUtil(getApplicationContext());
storage.storeShuffleRepeat("Shuffle", shuffle);
}
public void setRepeat(){
if(repeat) repeat=false;
else repeat=true;
StorageUtil storage = new StorageUtil(getApplicationContext());
storage.storeShuffleRepeat("Repeat", repeat);
}
}
将该服务添加到您的清单中。
<service android:name=".service.MediaPlayerService" />
在MainActivity中绑定服务并声明调用服务的方法。
public class MainActivity {
private MediaPlayerService player;
boolean serviceBound = false;
public static final String Broadcast_PLAY_NEW_AUDIO = "pkg_name.PlayNewAudio";
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
MediaPlayerService.LocalBinder binder = (MediaPlayerService.LocalBinder) service;
player = binder.getService();
serviceBound = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
serviceBound = false;
}
};
public void playAudio(int audioIndex, ArrayList<PlayableTrack> updatedList) {
audioList = updatedList;
if (!serviceBound) {
Intent playerIntent = new Intent(this, MediaPlayerService.class);
startService(playerIntent);
bindService(playerIntent, serviceConnection, Context.BIND_AUTO_CREATE);
} else {
Intent broadcastIntent = new Intent(Broadcast_PLAY_NEW_AUDIO);
sendBroadcast(broadcastIntent);
}
}
public void start() {
player.playMedia();
}
public void pause() {
player.pauseMedia();
}
public boolean isPlaying() {
if (player != null && serviceBound) {
return player.isPlaying();
}
return false;
}
}