我制作了一个简单的音乐播放器,可以在后台播放一些歌曲。转到主屏幕并通过通知重新打开应用程序。我唯一的问题是,当音乐播放完成后,如果我在音乐播放器活动中按下后退按钮(转到父活动),我的应用程序崩溃了。如何解决此问题?
playmusic.java
@Override
public void onDestroy() {
currentSongIndex = -1;
mHandler.removeCallbacks(mUpdateTimeTask);
Log.d("Player Service", "Player Service Stopped");
if (mp != null) {
if (mp.isPlaying()) {
mp.stop();
}
mp.release();
}
if (phoneStateListener != null) {
telephonyManager.listen(phoneStateListener,
PhoneStateListener.LISTEN_NONE);
}
// --Unregister headsetReceiver
unregisterReceiver(headsetReceiver);
super.onDestroy();
}
playerservice
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
if (!PlayerService.mp.isPlaying()) {
stopService(playerService);
}
super.onDestroy();
}
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.kaveh.googleplay2, PID: 29453 java.lang.RuntimeException: Unable to start service com.example.kaveh.googleplay2.PlayerService@527b4da4 with null: java.lang.NullPointerException at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2705) at android.app.ActivityThread.access$2100(ActivityThread.java:135) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1293) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:136) at android.app.ActivityThread.main(ActivityThread.java:5001) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601) at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.NullPointerException at com.example.kaveh.googleplay2.PlayerService.initUI(PlayerService.java:311) at com.example.kaveh.googleplay2.PlayerService.onStartCommand(PlayerService.java:142) at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2688) at android.app.ActivityThread.access$2100(ActivityThread.java:135) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1293) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:136) at android.app.ActivityThread.main(ActivityThread.java:5001) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601) at dalvik.system.NativeStart.main(Native Method) 08-25 13:37:06.274 543-29470/system_process D/dalvikvm: GC_FOR_ALLOC freed 1760K, 28% free 10140K/14056K, paused 10ms, total 10ms 08-25 13:37:07.326 543-590/system_process D/MobileDataStateTracker: default: setPolicyDataEnable(enabled=true) 08-25 13:37:07.694 29453-29453/com.example.kaveh.googleplay2 I/Process: Sending signal. PID: 29453 SIG: 9 08-25 13:37:07.694 543-590/system_process D/MobileDataStateTracker: default: setPolicyDataEnable(enabled=true)
修改 PlayerService.java
public class PlayerService extends Service implements
OnClickListener, MediaPlayer.OnInfoListener,
SeekBar.OnSeekBarChangeListener, MediaPlayer.OnBufferingUpdateListener
, OnPreparedListener, MediaPlayer.OnErrorListener, MediaPlayer.OnSeekCompleteListener
, MediaPlayer.OnCompletionListener {
private WeakReference<ImageView> btnPlay, btnForward, btnBackward;
private WeakReference<SeekBar> songProgressBar;
private WeakReference<TextView> songCurrentDurationLabel;
private WeakReference<TextView> songTotalDurationLabel;
public static MediaPlayer mp;
// Handler to update UI timer, progress bar etc,.
static Handler mHandler = new Handler();
// private SongsManager songManager;
private Utility utils;
private int seekForwardTime = 5000; // 5000 milliseconds
private int seekBackwardTime = 5000; // 5000 milliseconds
public static int currentSongIndex = -1;
public static int songindexForPause = 0;
// Set up broadcast identifier and intent
public static final String BROADCAST_BUFFER = "com.9android.net.broadcastbuffer";
Intent bufferIntent;
private boolean isPausedInCall = false;
private PhoneStateListener phoneStateListener;
private TelephonyManager telephonyManager;
private static final String TAG = "TELEPHONESERVICE";
Notification status;
private final String LOG_TAG = "NotificationService";
/**
* 29 * The BroadCast Receiver is used to listen system broadcast intent when
* 30 * headsets gets unplugged. If headset gets unplugged, stop music and
* 31 * service.
* 32
*/
private int headsetSwitch = 1;
private BroadcastReceiver headsetReceiver = new BroadcastReceiver() {
private boolean headsetConnected = false;
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
// Log.v(TAG, "ACTION_HEADSET_PLUG Intent received");
if (intent.hasExtra("state")) {
if (headsetConnected && intent.getIntExtra("state", 0) == 0) {
headsetConnected = false;
headsetSwitch = 0;
} else if (!headsetConnected
&& intent.getIntExtra("state", 0) == 1) {
headsetConnected = true;
headsetSwitch = 1;
}
}
switch (headsetSwitch) {
case (0):
headsetDisconnected();
break;
case (1):
break;
}
}
};
@Override
public void onCreate() {
// TODO Auto-generated method stub
mp = new MediaPlayer();
mp.setOnCompletionListener(this);
mp.setOnErrorListener(this);
mp.setOnPreparedListener(this);
mp.setOnBufferingUpdateListener(this);
mp.setOnSeekCompleteListener(this);
mp.setOnInfoListener(this);
mp.reset();
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);//
utils = new Utility();
// Instantiate bufferIntent to communicate with Activity for progress
// dialogue
bufferIntent = new Intent(BROADCAST_BUFFER);
// Register headset receiver
registerReceiver(headsetReceiver, new IntentFilter(
Intent.ACTION_HEADSET_PLUG));
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
initUI();
Bundle extera = intent.getExtras();
if (extera != null) {
String songLink = extera.getString("songLink");
Log.d("SongLink", "SongLink = " + songLink);
if (songLink.compareTo("") != 0)
playSong(songLink);
telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
phoneStateListener = new PhoneStateListener() {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
Log.v(TAG, "Starting CallStateChange");
switch (state) {
case TelephonyManager.CALL_STATE_OFFHOOK:
case TelephonyManager.CALL_STATE_RINGING:// incoming call
if (mp != null) {
pauseMedia();
isPausedInCall = true;
}
break;
case TelephonyManager.CALL_STATE_IDLE:// call finish
if (mp != null) {
if (isPausedInCall) {
isPausedInCall = false;
playMedia();
}
}
break;
}
}
};
telephonyManager.listen(phoneStateListener,
PhoneStateListener.LISTEN_CALL_STATE);
if (intent.getAction().equals(Constants.ACTION.STARTFOREGROUND_ACTION)) {
showNotification();
Toast.makeText(this, "Service Started", Toast.LENGTH_SHORT).show();
}
} else {
if (intent.getAction().equals(Constants.ACTION.PREV_ACTION)) {
Toast.makeText(this, "Clicked Previous", Toast.LENGTH_SHORT).show();
Log.i(LOG_TAG, "Clicked Previous");
} else if (intent.getAction().equals(Constants.ACTION.PLAY_ACTION)) {
Toast.makeText(this, "Clicked Play", Toast.LENGTH_SHORT).show();
Log.i(LOG_TAG, "Clicked Play");
if (mp.isPlaying()) {
if (mp != null) {
mp.pause();
btnPlay.get().setImageResource(R.drawable.play);
Log.d("Player Service", "Pause");
}
} else {
// Resume song
if (mp != null) {
mp.start();
RemoteViews views = new RemoteViews(getPackageName(),
R.layout.status_bar);
RemoteViews bigViews = new RemoteViews(getPackageName(),
R.layout.status_bar_expanded);
views.setImageViewResource(R.id.status_bar_play,
R.drawable.apollo_holo_dark_play);
bigViews.setImageViewResource(R.id.status_bar_play,
R.drawable.apollo_holo_dark_play);
// Changing button image to pause button
btnPlay.get().setImageResource(R.drawable.pause);
}
}
}
// else if (intent.getAction().equals(Constants.ACTION.NEXT_ACTION)) {
// Toast.makeText(this, "Clicked Next", Toast.LENGTH_SHORT).show();
// Log.i(LOG_TAG, "Clicked Next");
// }
else if (intent.getAction().equals(
Constants.ACTION.STOPFOREGROUND_ACTION)) {
Log.i(LOG_TAG, "Received Stop Foreground Intent");
Toast.makeText(this, "Service Stoped", Toast.LENGTH_SHORT).show();
stopForeground(true);
stopSelf();
}
} String songLink = intent.getExtras().getString("songLink");
Log.d("SongLink", "SongLink = " + songLink);
if (songLink.compareTo("") != 0)
playSong(songLink);
// Manage incoming phone calls during playback. Pause mp on incoming,
// resume on hangup.
// Get the telephony manager
telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
phoneStateListener = new PhoneStateListener() {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
// String stateString = "N/A";
Log.v(TAG, "Starting CallStateChange");
switch (state) {
case TelephonyManager.CALL_STATE_OFFHOOK:
case TelephonyManager.CALL_STATE_RINGING:// incoming call
if (mp != null) {
pauseMedia();
isPausedInCall = true;
} break;
case TelephonyManager.CALL_STATE_IDLE:// call finish
// Phone idle. Start playing.
if (mp != null) {
if (isPausedInCall) {
isPausedInCall = false;
playMedia();
}
}
break;
}
}
};
// Register the listener with the telephony manager
telephonyManager.listen(phoneStateListener,
PhoneStateListener.LISTEN_CALL_STATE);
super.onStart(intent, startId);
return START_STICKY;
}
/**
* 131 * @author 9Android.net
* 132
*/
private void initUI() {
songCurrentDurationLabel = new WeakReference(
PlayMusic.songCurrentDurationLabel);
songTotalDurationLabel = new WeakReference(
PlayMusic.songTotalDurationLabel);
btnPlay = new WeakReference(PlayMusic.btnPlay);
btnForward = new WeakReference(PlayMusic.btnForward);
btnBackward = new WeakReference(PlayMusic.btnBackward);
btnPlay.get().setOnClickListener(this);
btnForward.get().setOnClickListener(this);
btnBackward.get().setOnClickListener(this);
songProgressBar = new WeakReference(
PlayMusic.songProgressBar);
songProgressBar.get().setOnSeekBarChangeListener(this);
}
// Send a message to Activity that audio is being prepared and buffering
// started.
private void sendBufferingBroadcast() {
// Log.v(TAG, "BufferStartedSent");
bufferIntent.putExtra("buffering", "1");
sendBroadcast(bufferIntent);
}
// Send a message to Activity that audio is prepared and ready to start
// playing.
private void sendBufferCompleteBroadcast() {
bufferIntent.putExtra("buffering", "0");
sendBroadcast(bufferIntent);
}
// -------------------------------------------------------------------------//
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.btn_play:
if (mp.isPlaying()) {
if (mp != null) {
mp.pause();
// Changing button image to play button
btnPlay.get().setImageResource(R.drawable.play);
Log.d("Player Service", "Pause");
}
} else {
// Resume song
if (mp != null) {
mp.start();
// Changing button image to pause button
btnPlay.get().setImageResource(R.drawable.pause);
}
}
break;
case R.id.btn_forward:
// get current song position
int currentPosition = mp.getCurrentPosition();
// check if seekForward time is lesser than song duration
if (currentPosition + seekForwardTime <= mp.getDuration()) { // forward song mp.seekTo(currentPosition + seekForwardTime); } else { // forward to end position mp.seekTo(mp.getDuration()); } break; case R.id.btn_backward: // get current song position int currentPosition2 = mp.getCurrentPosition(); // check if seekBackward time is greater than 0 sec if (currentPosition2 - seekBackwardTime >= 0) {
// forward song
mp.seekTo(currentPosition + seekBackwardTime);
} else {
// backward to starting position
mp.seekTo(0);
}
break;
}
}
// -------------------------------------------------------------//
public void playSong(String songPath) {
mHandler.removeCallbacks(mUpdateTimeTask);
mp.reset();
if (!mp.isPlaying()) {
try {
mp.setDataSource(songPath);
// Send message to Activity to display progress dialogue
sendBufferingBroadcast();
mp.prepareAsync();
// Changing Button Image to pause image
btnPlay.get().setImageResource(R.drawable.pause);
// set Progress bar values
songProgressBar.get().setProgress(0);
songProgressBar.get().setMax(100);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// Called when the media file is ready for playback.--------------------//
public void onPrepared(MediaPlayer mp) {
// Send a message to activity to end progress dialogue
sendBufferCompleteBroadcast();
playMedia();
}
public void playMedia() {
if (!mp.isPlaying()) {
mp.start();
updateProgressBar();
}
}
// Add for Telephony Manager
public void pauseMedia() {
// Log.v(TAG, "Pause Media");
if (mp.isPlaying()) {
mp.pause();
}
}
public void stopMedia() {
if (mp.isPlaying()) {
mp.stop();
}
}
/**
* 264 * Update timer on seekbar
* 265 *
*/
public void updateProgressBar() {
mHandler.postDelayed(mUpdateTimeTask, 100);
}
/**
* 271 * Background Runnable thread
* 272 *
*/
private Runnable mUpdateTimeTask = new Runnable() {
public void run() {
long totalDuration = 0;
try {
totalDuration = mp.getDuration();
} catch (IllegalStateException e) {
e.printStackTrace();
}
long currentDuration = 0;
try {
currentDuration = mp.getCurrentPosition();
} catch (IllegalStateException e) {
e.printStackTrace();
}
songTotalDurationLabel.get().setText(
"" + utils.milliSecondsToTimer(totalDuration));
songCurrentDurationLabel.get().setText(
"" + utils.milliSecondsToTimer(currentDuration));
// Updating progress bar
int progress = (int) (utils.getProgressPercentage(currentDuration,
totalDuration));
// Log.d("Progress", ""+progress);
songProgressBar.get().setProgress(progress);
// Running this thread after 100 milliseconds
mHandler.postDelayed(this, 100);
}
};
/**
* 306 * onProgressChanged
* 307
*/
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromTouch) {
}
/**
* 314 * When user starts moving the progress handler
* 315 *
*/
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
// remove message Handler from updating progress bar
mHandler.removeCallbacks(mUpdateTimeTask);
}
/**
* 323 * When user stops moving the progress hanlder
* 324 *
*/
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
mHandler.removeCallbacks(mUpdateTimeTask);
int totalDuration = mp.getDuration();
int currentPosition = utils.progressToTimer(seekBar.getProgress(),
totalDuration);
// forward or backward to certain seconds
mp.seekTo(currentPosition);
// update timer progress again
updateProgressBar();
}
/**
* 339 * On Song Playing completed if repeat is ON play same song again if shuffle
* 340 * is ON play random song
* 341 *
*/
@Override
public void onCompletion(MediaPlayer arg0) {
mp.stop();
mp.release();
}
@Override
public void onDestroy() {
currentSongIndex = -1;
mHandler.removeCallbacks(mUpdateTimeTask);
Log.d("Player Service", "Player Service Stopped");
if (mp != null) {
if (mp.isPlaying()) {
mp.stop();
}
mp.release();
}
if (phoneStateListener != null) {
telephonyManager.listen(phoneStateListener,
PhoneStateListener.LISTEN_NONE);
}
// --Unregister headsetReceiver
unregisterReceiver(headsetReceiver);
super.onDestroy();
}
@Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
return false;
}
@Override
public void onSeekComplete(MediaPlayer mp) {
}
@Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
}
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
return false;
}
private void headsetDisconnected() {
pauseMedia();
}
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
private void showNotification() {
// Using RemoteViews to bind custom layouts into Notification
RemoteViews views = new RemoteViews(getPackageName(),
R.layout.status_bar);
RemoteViews bigViews = new RemoteViews(getPackageName(),
R.layout.status_bar_expanded);
// showing default album image
views.setViewVisibility(R.id.status_bar_icon, View.VISIBLE);
views.setViewVisibility(R.id.status_bar_album_art, View.GONE);
bigViews.setImageViewBitmap(R.id.status_bar_album_art,
Constants.getDefaultAlbumArt(this));
Intent notificationIntent = new Intent(this, PlayMusic.class);
notificationIntent.setAction(Constants.ACTION.MAIN_ACTION);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
// Intent previousIntent = new Intent(this, PlayerService.class);
// previousIntent.setAction(Constants.ACTION.PREV_ACTION);
// PendingIntent ppreviousIntent = PendingIntent.getService(this, 0,
// previousIntent, 0);
Intent playIntent = new Intent(this, PlayerService.class);
playIntent.setAction(Constants.ACTION.PLAY_ACTION);
PendingIntent pplayIntent = PendingIntent.getService(this, 0,
playIntent, 0);
Intent nextIntent = new Intent(this, PlayerService.class);
nextIntent.setAction(Constants.ACTION.NEXT_ACTION);
PendingIntent pnextIntent = PendingIntent.getService(this, 0,
nextIntent, 0);
Intent closeIntent = new Intent(this, PlayerService.class);
closeIntent.setAction(Constants.ACTION.STOPFOREGROUND_ACTION);
PendingIntent pcloseIntent = PendingIntent.getService(this, 0,
closeIntent, 0);
views.setOnClickPendingIntent(R.id.status_bar_play, pplayIntent);
bigViews.setOnClickPendingIntent(R.id.status_bar_play, pplayIntent);
views.setOnClickPendingIntent(R.id.status_bar_next, pnextIntent);
bigViews.setOnClickPendingIntent(R.id.status_bar_next, pnextIntent);
// views.setOnClickPendingIntent(R.id.status_bar_prev, ppreviousIntent);
// bigViews.setOnClickPendingIntent(R.id.status_bar_prev, ppreviousIntent);
views.setOnClickPendingIntent(R.id.status_bar_collapse, pcloseIntent);
bigViews.setOnClickPendingIntent(R.id.status_bar_collapse, pcloseIntent);
views.setImageViewResource(R.id.status_bar_play,
R.drawable.apollo_holo_dark_pause);
bigViews.setImageViewResource(R.id.status_bar_play,
R.drawable.apollo_holo_dark_pause);
// views.setTextViewText(R.id.status_bar_artist_name, "Artist Name");
// bigViews.setTextViewText(R.id.status_bar_artist_name, "Artist Name");
//
// bigViews.setTextViewText(R.id.status_bar_album_name, "Album Name");
status = new Notification.Builder(this).build();
status.contentView = views;
status.bigContentView = bigViews;
status.flags = Notification.FLAG_ONGOING_EVENT;
status.icon = R.drawable.ic_launcher;
status.contentIntent = pendingIntent;
startForeground(Constants.NOTIFICATION_ID.FOREGROUND_SERVICE, status);
}
}