我正在为mediaPlayer App使用媒体播放器服务,我在一个活动中使用该媒体播放器的实例 . 现在,当我使用按钮或通知更改音乐时,currentmedia Player对下一首歌无效 . 新mediaPlayer的信息更新实际上有延迟 .
当我使用2000ms的handler.postDelayed时,我可以从Service获得正确的mediaPlayer,但是没有延迟它没有给出实例 .
问题是:使用媒体会话控件时为什么会出现延迟?对于手动更换轨道等情况也是如此 .
Class Name : MediaPlayerSerice
public class MediaPlayerService extends Service implements MediaPlayer.OnCompletionListener, MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener, MediaPlayer.OnSeekCompleteListener,
MediaPlayer.OnInfoListener, MediaPlayer.OnBufferingUpdateListener,
AudioManager.OnAudioFocusChangeListener,AsyncInterface {
public static final String TAG = MediaPlayerService.class.getSimpleName();
public static final String ACTION_PLAY = "com.natit.kambo.ACTION_PLAY";
public static final String ACTION_PAUSE = "com.natit.kambo.ACTION_PAUSE";
public static final String ACTION_PREVIOUS = "com.natit.kambo.ACTION_PREVIOUS";
public static final String ACTION_NEXT = "com.natit.kambo.ACTION_NEXT";
public static final String ACTION_STOP = "com.natit.kambo.ACTION_STOP";
public static final String ACTION_PLAY_NOTIFICATION = "com.natit.kambo.ACTION_PLAY_NOTIFICATION";
public static final String ACTION_PAUSE_NOTIFICATION = "com.natit.kambo.ACTION_PAUSE_NOTIFICATION";
public static final String ACTION_PREVIOUS_NOTIFICATION = "com.natit.kambo.ACTION_PREVIOUS_NOTIFICATION";
public static final String ACTION_NEXT_NOTIFICATION = "com.natit.kambo.ACTION_NEXT_NOTIFICATION";
public static final String ACTION_STOP_NOTIFICATION= "com.natit.kambo.ACTION_STOP_NOTIFICATION";
public static final String GLOBAL_AUDIO_PLAYING= "com.natit.kambo.ACTION_GLOBAL_AUDIO_PLAYING";
public static final String GLOBAL_AUDIO_PAUSED= "com.natit.kambo.ACTION_GLOBAL_AUDIO_PAUSED";
public static final String GLOBAL_AUDIO_COMPLETED= "com.natit.kambo.ACTION_GLOBAL_AUDIO_COMPLETED";
public static final String GLOBAL_AUDIO_BUFFERING= "com.natit.kambo.ACTION_GLOBAL_AUDIO_BUFFERING";
public static final String GLOBAL_AUDIO_NOT_BUFFERING= "com.natit.kambo.ACTION_GLOBAL_AUDIO_NOT_BUFFERING";
public static final String GLOBAL_MEDIA_PLAYER_PREPARED = "com.natit.kambo.ACTION_GLOBAL_MEDIA_PLAYER_PREPARED";
public static final String GLOBAL_MEDIA_PLAYER_NEW_SONG_STARTED = "com.natit.kambo.ACTION_GLOBAL_MEDIA_PLAYER_NEW_SONG_STARTED";
private MediaSessionManager mediaSessionManager;
private MediaSessionCompat mediaSession;
private MediaControllerCompat.TransportControls transportControls;
private Bitmap bitmapImage;
AsyncInterface asyncInterface;
private static final int NOTIFICATION_ID = 47;
private MediaPlayer mediaPlayer ;
private AudioManager audioManager;
private boolean ongoingCall = false;
private PhoneStateListener phoneStateListener;
private TelephonyManager telephonyManager;
//List of available Audio files
private ArrayList<OfflineSong> audioList;
private int audioIndex = -1;
private OfflineSong activeAudio; //an object of the currently playing audio
//Used to pause/resume MediaPlayer
private int resumePosi;
@Override
public void onCreate() {
super.onCreate();
mediaPlayer = new MediaPlayer();
asyncInterface = this;
callStateListener();
registerReceiver(becomingNoisyReceiver, new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
registerReceiver(playNewAudioBr, new IntentFilter(HomeActivity.Broadcast_PLAY_NEW_AUDIO));
registerReceiver(pauseBr, new IntentFilter(HomeActivity.ACTION_PAUSE1));
registerReceiver(playBr, new IntentFilter(HomeActivity.ACTION_PLAY1));
registerReceiver(onPlayNextBr, new IntentFilter(HomeActivity.ACTION_PLAY_NEXT1));
registerReceiver(onPlayPrevBr, new IntentFilter(HomeActivity.ACTION_PLAY_PREV1));
}
/**************************
* READY MEDIA PLAYER
***************************/
private void readyMediaPlayer() {
//Set up MediaPlayer event listeners
mediaPlayer.setOnCompletionListener(this);
mediaPlayer.setOnErrorListener(this);
mediaPlayer.setOnPreparedListener(this);
mediaPlayer.setOnBufferingUpdateListener(this);
mediaPlayer.setOnSeekCompleteListener(this);
mediaPlayer.setOnInfoListener(this);
mediaPlayer.reset();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
mediaPlayer.setDataSource(activeAudio.getFilename());
} catch (IOException e)
{
//stopSelf();
}
mediaPlayer.prepareAsync();
}
/******************
* ON PREPARED
******************/
@Override
public void onPrepared(MediaPlayer mp) {
playMedia();
sendBroadcast(new Intent(GLOBAL_MEDIA_PLAYER_PREPARED));
}
/***********************************
* ON START COMMAND,from service class
************************************/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
StoragePreference storage = new StoragePreference(getApplicationContext());
audioList = storage.loadAudio();
audioIndex = storage.loadAudioIndex();
if (audioIndex != -1 && audioIndex < audioList.size())
{
activeAudio = audioList.get(audioIndex);
}
else
{
stopSelf();
}
}
catch (NullPointerException e) {
stopSelf();
}
if (!requestAudioFocus())
{
stopSelf();
}
if (mediaSessionManager == null)
{
try
{
initMediaSession();
readyMediaPlayer();
}
catch (RemoteException e)
{
e.printStackTrace();
stopSelf();
}
buildNotification(PlaybackStatus.PLAYING);
}
handleIncomingActions(intent); //\\ INTENTS FROM BUTTONS //\\
return super.onStartCommand(intent, flags, startId);
}
private void playMedia() {
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
sendBroadcast(new Intent(GLOBAL_AUDIO_PLAYING));
}
}
private void stopMedia() {
if (mediaPlayer == null) return;
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
}
private void pauseMedia() {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
resumePosi = mediaPlayer.getCurrentPosition();
sendBroadcast(new Intent(GLOBAL_AUDIO_PAUSED));
}
}
private void resumeMedia() {
if (!mediaPlayer.isPlaying()) {
mediaPlayer.seekTo(resumePosi);
mediaPlayer.start();
sendBroadcast(new Intent(GLOBAL_AUDIO_PLAYING));
}
}
@Override
public void getBitMap(Bitmap bitmap) {
bitmapImage = bitmap;
}
/************************************************************
* BINDER FOR ATTACHING TO OTHER ACTIVITIES, From Service Class
*************************************************************/
private final IBinder iBinder = new MusicServiceBinder();
public class MusicServiceBinder extends Binder // implementing the abstruct class Binder
{
public MediaPlayerService getService()
{
return MediaPlayerService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return iBinder;
}
/************************
* BUFFER DETECTION
*************************/
@Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
//sendBroadcast(new Intent(GLOBAL_AUDIO_BUFFERING));
}
/******************************
* MEDIA PLAYER ON COMPLETION
*******************************/
@Override
public void onCompletion(MediaPlayer mp) {
Log.e(TAG, "onCompletion: is called");
stopMedia();
sendBroadcast(new Intent(GLOBAL_AUDIO_COMPLETED));
}
/************************
* ON AUDIO FOCUS CHANGE
************************/
@Override
public void onAudioFocusChange(int focusChange) {
//Invoked when the audio focus of the system is updated.
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN:
// resume playback
if (mediaPlayer == null) readyMediaPlayer();
else if (!mediaPlayer.isPlaying()) mediaPlayer.start();
mediaPlayer.setVolume(1.0f, 1.0f);
break;
case AudioManager.AUDIOFOCUS_LOSS:
// Lost focus for an unbounded amount of time: stop playback and release media player
if (mediaPlayer.isPlaying()) mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
// Lost focus for a short time, but we have to stop
// playback. We don't release the media player because playback
// is likely to resume
if (mediaPlayer.isPlaying()) mediaPlayer.pause();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
// Lost focus for a short time, but it's ok to keep playing
// at an attenuated level
if (mediaPlayer.isPlaying()) mediaPlayer.setVolume(0.1f, 0.1f);
break;
}
}
/************************
* REQUEST FOCUS
************************/
private boolean requestAudioFocus() {
audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
return true;
}
else {
return false;
}
}
/************************
* REMOVE FOCUS
************************/
private boolean removeAudioFocus() {
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED == audioManager.abandonAudioFocus(this);
}
//Handle incoming phone calls
private void callStateListener() {
// Get the telephony manager
telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
//Starting listening for PhoneState changes
phoneStateListener = new PhoneStateListener() {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
//if at least one call exists or the phone is ringing
//pause the MediaPlayer
case TelephonyManager.CALL_STATE_OFFHOOK:
case TelephonyManager.CALL_STATE_RINGING:
if (mediaPlayer != null) {
pauseMedia();
ongoingCall = true;
}
break;
case TelephonyManager.CALL_STATE_IDLE:
// Phone idle. Start playing.
if (mediaPlayer != null) {
if (ongoingCall) {
ongoingCall = false;
resumeMedia();
}
}
break;
}
}
};
// Register the listener with the telephony manager
// Listen for changes to the device call state.
telephonyManager.listen(phoneStateListener,PhoneStateListener.LISTEN_CALL_STATE);
}
/*****************************
* For Responding to BROADCAST
*****************************/
BroadcastReceiver playNewAudioBr = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
audioIndex = new StoragePreference(getApplicationContext()).loadAudioIndex();
if (audioIndex != -1 && audioIndex < audioList.size()) {
activeAudio = audioList.get(audioIndex);
} else {
stopSelf();
}
stopMedia();
mediaPlayer.reset();
readyMediaPlayer();
updateMetaData();
buildNotification(PlaybackStatus.PLAYING);
}
};
BroadcastReceiver playBr = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
playMedia();
updateMetaData();
buildNotification(PlaybackStatus.PLAYING);
}
};
BroadcastReceiver pauseBr = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
pauseMedia();
buildNotification(PlaybackStatus.PAUSED);
}
};
BroadcastReceiver becomingNoisyReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//pause audio on ACTION_AUDIO_BECOMING_NOISY
pauseMedia();
// buildNotification(PlaybackStatus.PAUSED);
}
};
BroadcastReceiver onPlayNextBr = new BroadcastReceiver() {
public void onReceive(Context ctxt, Intent intent) {
skipToNext();
updateMetaData();
}
};
BroadcastReceiver onPlayPrevBr = new BroadcastReceiver() {
public void onReceive(Context ctxt, Intent intent) {
skipToPrevious();
updateMetaData();
}
};
/************************************
* ON DESTROY, from service Class
***********************************/
@Override
public void onDestroy() {
super.onDestroy();
if (mediaPlayer != null) {
stopMedia();
mediaPlayer.release();
}
removeAudioFocus();
//Disable the PhoneStateListener
if (phoneStateListener != null) {
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
}
removeNotification();
unregisterReceiver(becomingNoisyReceiver);
unregisterReceiver(playNewAudioBr);
unregisterReceiver(pauseBr);
unregisterReceiver(playBr);
unregisterReceiver(onPlayNextBr);
unregisterReceiver(onPlayPrevBr);
//clear cached playlist
new StoragePreference(getApplicationContext()).clearCachedAudioPlaylist();
}
/*********************
* INIT MEDIA SESSION
*********************/
private void initMediaSession() throws RemoteException {
if (mediaSessionManager != null)
return;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
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();
buildNotification(PlaybackStatus.PLAYING);
}
@Override
public void onPause() {
super.onPause();
pauseMedia();
buildNotification(PlaybackStatus.PAUSED);
}
@Override
public void onSkipToNext() {
super.onSkipToNext();
skipToNext();
updateMetaData();
buildNotification(PlaybackStatus.PLAYING);
}
@Override
public void onSkipToPrevious() {
super.onSkipToPrevious();
skipToPrevious();
updateMetaData();
buildNotification(PlaybackStatus.PLAYING);
}
@Override
public void onStop() {
super.onStop();
removeNotification();
//Stop the service
stopSelf();
}
@Override
public void onSeekTo(long position) {
super.onSeekTo(position);
}
});
}
/************************
* META DATA UPDATE
************************/
private void updateMetaData() {
new DownloadImageTask(activeAudio.getArtwork(),MediaPlayerService.this).execute(activeAudio.getArtwork());
Bitmap albumArt = bitmapImage;
mediaSession.setMetadata(new MediaMetadataCompat.Builder()
.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, albumArt)
.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, activeAudio.getArtistName())
.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, activeAudio.getAlbumName())
.putString(MediaMetadataCompat.METADATA_KEY_TITLE, activeAudio.getName())
.build());
}
/************************
* SKIP TO NEXT
************************/
private void skipToNext() {
if (audioIndex == audioList.size() - 1) {
//if last in playlist
audioIndex = 0;
activeAudio = audioList.get(audioIndex);
} else {
//get next in playlist
activeAudio = audioList.get(++audioIndex);
}
//Update stored index
new StoragePreference(getApplicationContext()).storeAudioIndex(audioIndex);
stopMedia();
//reset mediaPlayer
mediaPlayer.reset();
readyMediaPlayer();
updateMetaData();
}
/************************
* SKIP TO PREVIOUS
************************/
private void skipToPrevious() {
if (audioIndex == 0) {
//if first in playlist
//set index to the last of audioList
audioIndex = audioList.size() - 1;
activeAudio = audioList.get(audioIndex);
} else {
//get previous in playlist
activeAudio = audioList.get(--audioIndex);
}
//Update stored index
new StoragePreference( getApplicationContext()).storeAudioIndex(audioIndex);
stopMedia();
//reset mediaPlayer
mediaPlayer.reset();
readyMediaPlayer();
}
/************************
* NOTIFICATION BUILDER
************************/
private void buildNotification(PlaybackStatus playbackStatus) {
int notificationIcon = android.R.drawable.ic_media_pause;
PendingIntent pedningIntent = null;
if (playbackStatus == PlaybackStatus.PLAYING) {
notificationIcon = android.R.drawable.ic_media_pause;
pedningIntent = playbackAction(1);
}
else if (playbackStatus == PlaybackStatus.PAUSED) {
notificationIcon = android.R.drawable.ic_media_play;
//create the play action
pedningIntent = playbackAction(0);
}
Bitmap largeIcon = BitmapFactory.decodeResource(getResources(),
R.drawable.ic_placeholder); //replace with your own image
// Create a new Notification
NotificationCompat.Builder notificationBuilder = (NotificationCompat.Builder) new NotificationCompat.Builder(this)
.setShowWhen(false)
.setOngoing(true)
// Set the Notification style
.setStyle(new android.support.v4.media.app.NotificationCompat.MediaStyle()
// Attach our MediaSession token
.setMediaSession(mediaSession.getSessionToken())
// Show our playback controls in the compact notification view.
.setShowActionsInCompactView(0, 1, 2))
// Set the Notification color
.setColor(getResources().getColor(R.color.colorPrimary))
// Set the large and small icons
.setLargeIcon(largeIcon)
.setSmallIcon(android.R.drawable.stat_sys_headset)
// Set Notification content information
.setContentText(activeAudio.getArtistName())
.setContentTitle(activeAudio.getAlbumName())
.setContentInfo(activeAudio.getName())
// Add playback actions
.addAction(android.R.drawable.ic_media_previous, "previous", playbackAction(3))
.addAction(notificationIcon, "pause", pedningIntent)
.addAction(android.R.drawable.ic_media_next, "next", playbackAction(2));
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).notify(NOTIFICATION_ID, notificationBuilder.build());
}
/************************
* REMOVE NOTIFICATION
************************/
private void removeNotification() {
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(NOTIFICATION_ID);
}
/************************
* PENDING INTENTS
************************/
private PendingIntent playbackAction(int actionNumber) {
Intent playbackAction = new Intent(this, MediaPlayerService.class);
switch (actionNumber)
{
case 0:
// Play
playbackAction.setAction(ACTION_PLAY);
return PendingIntent.getService(this, actionNumber, playbackAction, 0);
case 1:
// Pause
playbackAction.setAction(ACTION_PAUSE);
return PendingIntent.getService(this, actionNumber, playbackAction, 0);
case 2:
// Next track
playbackAction.setAction(ACTION_NEXT);
return PendingIntent.getService(this, actionNumber, playbackAction, 0);
case 3:
// Previous track
playbackAction.setAction(ACTION_PREVIOUS);
return PendingIntent.getService(this, actionNumber, playbackAction, 0);
default:
break;
}
return null;
}
/**************************************************************************************************************
*USING TRANSPORT CONTROL FOR CONTROLLING MEDIA PLAYBACKS,AND SENDING BROADCASTS FOR OTHER ACTIVITIES.
***************************************************************************************************************/
private void handleIncomingActions(Intent playbackAction) {
if (playbackAction == null || playbackAction.getAction() == null)
return;
String actionString = playbackAction.getAction();
if (actionString.equalsIgnoreCase(ACTION_PLAY)) {
transportControls.play();
sendBroadcast( new Intent(ACTION_PLAY_NOTIFICATION));
} else if (actionString.equalsIgnoreCase(ACTION_PAUSE)) {
transportControls.pause();
sendBroadcast(new Intent(ACTION_PAUSE_NOTIFICATION));
} else if (actionString.equalsIgnoreCase(ACTION_NEXT)) {
transportControls.skipToNext();
sendBroadcast(new Intent(ACTION_NEXT_NOTIFICATION));
} else if (actionString.equalsIgnoreCase(ACTION_PREVIOUS)) {
transportControls.skipToPrevious();
sendBroadcast(new Intent(ACTION_PREVIOUS_NOTIFICATION));
} else if (actionString.equalsIgnoreCase(ACTION_STOP)) {
transportControls.stop();
sendBroadcast(new Intent(ACTION_STOP_NOTIFICATION));
}
}
public MediaPlayer getMediaPlayer() {
return mediaPlayer;
}
public int getAudioIndex(){
return audioIndex;
}
public MediaControllerCompat.TransportControls getTransportControls() {
return transportControls;
}
public OfflineSong getActiveAudio() {
return activeAudio;
}
public AudioManager getAudioManager() {
return audioManager;
}
}
现在在音乐活动中,我正在绑定服务,然后使用服务类的mediaplayer实例 . (getMediaPlayer()) .
当尝试更新持续时间等事情时会产生如下所示的问题:
现在每次播放新歌时都会出现错误:
08-14 11:59:25.596 31091-31091 / com.natit.kambo E / MediaPlayer:尝试在没有有效媒体播放器的情况下调用getDuration