我正在开发Android MusicPlayer。我创建了服务类扩展服务。在我的Main_activity中,我使用 startService()方法调用服务类,同时使用 Intent传递音乐列表。
private void sendDatatoService() {
if (playIntent == null) {
playIntent = new Intent(this, MusicService.class);
playIntent.putParcelableArrayListExtra("songList",list);
bindService(playIntent, musicConnection, Context.BIND_AUTO_CREATE);
startService(playIntent);
}
}
private final ServiceConnection musicConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
MusicService.PlayerBinder binder = (MusicService.PlayerBinder) service;
serviceMusic = binder.getService();
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e("serviceMusic::","onServiceDisconnected");
}
};
我的MusicPlayer工作正常,但是当我暂停一段时间并尝试再播放一些歌曲时,它崩溃说我的歌曲列表是空的。这里发生了什么,当Android杀死我的服务时,我应该从START_STICKY或其他任何一种服务开始保持我的数据可用于服务或重新获得列表?
@Override
public void onCreate() {
super.onCreate();
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// TODO: Done // creating a channel before creating a notification, needs channel to show notification in Android-O+ OS
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
initChannel();
}
//initializing media player, to play the music using MediaPlayer Api/class we need it to play the music
initMediaPlayer();
notificationCompatBuilder = new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID);
initNoisyReceiver();
}
public void initMediaPlayer() {
if (mPlayer == null) {
mPlayer = new MediaPlayer();
mPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mPlayer.setOnPreparedListener(this);
mPlayer.setOnCompletionListener(this);
mPlayer.setOnErrorListener(this);
}
}
public void updateNotification(String updatedSongName, int songPos) {
setBitmapImage(mListOfSongs.get(songPos).getAlbumArt());
mNotification = notificationCompatBuilder
.setSmallIcon(R.drawable.play_logo)
.setLargeIcon(bitmapImage)
.setOngoing(true)
.setColorized(true)
.setStyle(new NotificationCompat.DecoratedCustomViewStyle())
.setDefaults(Notification.DEFAULT_ALL)
.build();
mNotification.contentView.setTextViewText(R.id.notify_song_name, updatedSongName);
notificationManager.notify(NOTIFICATION_ID, mNotification);
String updatedAlbumName = mListOfSongs.get(songPos).getSongAlbumName();
String updatedArtistName = mListOfSongs.get(songPos).getSongArtist();
String updatedAlbumArt = mListOfSongs.get(songPos).getAlbumArt();
String updatedSongDuration = mListOfSongs.get(songPos).getSongDuration();
mCallback.onupdateClick(songPos, updatedSongName, updatedAlbumName, updatedArtistName, updatedAlbumArt, updatedSongDuration);
}
public class PlayerBinder extends Binder {
public MusicService getService() {
Log.d("test", "getService()");
return MusicService.this;
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.d("test", "onBind Called");
return musicBind;
}
@Override
public boolean onUnbind(Intent intent) {
if (mgr != null) {
mgr.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
}
//mAudioManager.abandonAudioFocus(this);
notificationManager.cancel(NOTIFICATION_ID);
return false;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
mListOfSongs = intent.getParcelableArrayListExtra("songList");
String Action = intent.getAction();
if (!TextUtils.isEmpty(Action)) {
switch (Action) {
case ACTION_PAUSE:
playPauseSong();
break;
case ACTION_NEXT:
nextSong();
break;
case ACTION_PREVIOUS:
previousSong();
break;
case ACTION_STOP:
stopSong();
stopSelf();
break;
}
}
}
return START_STICKY;
}
private void stopSong() {
if (mgr != null) {
mgr.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
}
if (mPlayer != null) {
if (mPlayer.isPlaying()) {
mPlayer.stop();
mPlayer.release();
} else {
mPlayer.release();
}
}
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.cancel(NOTIFICATION_ID);
System.exit(0);
}
public void previousSong() {
try {
if (SONG_POS == 0) {
Toast.makeText(this, "No Previous Song", Toast.LENGTH_SHORT).show();
return;
}
SONG_POS--;
startSong(Uri.parse(mListOfSongs.get(SONG_POS).getSongUri()), mListOfSongs.get(SONG_POS).getSongName(), SONG_POS);
} catch (Exception e) {
}
}
public void nextSong() {
// TODO: 10/1/2017 check if mListOfSongs is not empty otherwise it will show an error
if (mListOfSongs == null) {
Toast.makeText(this, "Restart the App", Toast.LENGTH_SHORT).show();
return;
}
if (SONG_POS >= mListOfSongs.size() - 1) {
SONG_POS = -1;
}
try {
SONG_POS++;
startSong(Uri.parse(mListOfSongs.get(SONG_POS).getSongUri()), mListOfSongs.get(SONG_POS).getSongName(), SONG_POS
);
} catch (Exception e) {
Toast.makeText(this, "No Next Song", Toast.LENGTH_SHORT).show();
startSong(Uri.parse(mListOfSongs.get(SONG_POS).getSongUri()), mListOfSongs.get(SONG_POS).getSongName(), SONG_POS);
}
}
public void startSong(Uri parseSongUri, String songName, int SONG_POS) {
//checkAudioFocus();
if (!successfullyRetrievedAudioFocus()) {
return;
}
mPlayer.reset();
mState = STATE_PLAYING;
mSongUri = parseSongUri;
try {
mPlayer.setDataSource(getApplicationContext(), mSongUri);
} catch (Exception e) {
Log.e("MUSIC SERVICE", "ERROR SETTING DATA SOURCE", e);
}
mPlayer.prepareAsync();
updateNotification(songName, SONG_POS);
}
public void playPauseSong() {
if (mPlayer == null) {
initMediaPlayer();
}
if (mState == STATE_PAUSED) {
mState = STATE_PLAYING;
mPlayer.start();
} else {
mState = STATE_PAUSED;
mPlayer.pause();
}
}
//starting media player when media player is ready
@Override
public void onPrepared(MediaPlayer mp) {
mPlayer.start();
}
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
mp.reset();
return false;
}
@Override
public void onCompletion(MediaPlayer mp) {
mPlayer.reset();
try {
if (SONG_POS < mListOfSongs.size() - 1) {
nextSong();
} else {
SONG_POS = 0;
mPlayer.setDataSource(getApplicationContext(), Uri.parse(mListOfSongs.get(SONG_POS).getSongUri()));
}
} catch (Exception e) {
Log.e("MUSIC SERVICE", "Error setting data source", e);
}
}
@Override
public void onAudioFocusChange(int focusChange) {
switch (focusChange) {
case AudioManager.AUDIOFOCUS_LOSS: {
if (mPlayer.isPlaying()) {
mPlayer.stop();
}
break;
}
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: {
mPlayer.pause();
break;
}
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: {
if (mPlayer != null) {
mPlayer.setVolume(0.3f, 0.3f);
}
break;
}
case AudioManager.AUDIOFOCUS_GAIN: {
if (mPlayer != null) {
if (!mPlayer.isPlaying()) {
mPlayer.start();
}
mPlayer.setVolume(1.0f, 1.0f);
}
break;
}
}
}
private void setSongURI(Uri mSongUri) {
this.mSongUri = mSongUri;
}
private void setBitmapImage(String albumArt) {
// Drawable img = Drawable.createFromPath(albumArt);
if (!albumArt.equals("null")) {
bitmapImage = BitmapFactory.decodeFile(albumArt);
} else {
bitmapImage = BitmapFactory.decodeResource(getResources(), R.drawable.beat_box_logo);
}
}
public void setSelectedSong(int pos, int notification_id, Context context, UpdateFromService listner) {
SONG_POS = pos;
this.mCallback = listner;
NOTIFICATION_ID = notification_id;
setSongURI(Uri.parse(mListOfSongs.get(SONG_POS).getSongUri()));
setBitmapImage(mListOfSongs.get(SONG_POS).getAlbumArt());
ShowNotification();
startSong(Uri.parse(mListOfSongs.get(SONG_POS).getSongUri()), mListOfSongs.get(SONG_POS).getSongName(), SONG_POS);
}
private void ShowNotification() {
PendingIntent pendingIntent, pendingIntentStop;
Intent intentStop, intentPause, intentPrevious, intentNext;
RemoteViews notificationView = new RemoteViews(getPackageName(), R.layout.notification_mediacontroller);
notificationView.setTextViewText(R.id.notify_song_name, mListOfSongs.get(SONG_POS).getSongName());
intentStop = new Intent(ACTION_STOP);
pendingIntentStop = PendingIntent.getService(getApplicationContext(), REQUEST_CODE_STOP, intentStop, PendingIntent.FLAG_CANCEL_CURRENT);
intentPause = new Intent(ACTION_PAUSE);
pendingIntent = PendingIntent.getService(getApplicationContext(), REQUEST_CODE_PAUSE, intentPause, PendingIntent.FLAG_UPDATE_CURRENT);
notificationView.setOnClickPendingIntent(R.id.notify_btn_pause, pendingIntent);
intentPrevious = new Intent(ACTION_PREVIOUS);
pendingIntent = PendingIntent.getService(getApplicationContext(), REQUEST_CODE_PREVIOUS, intentPrevious, PendingIntent.FLAG_UPDATE_CURRENT);
notificationView.setOnClickPendingIntent(R.id.notify_btn_previous, pendingIntent);
intentNext = new Intent(ACTION_NEXT);
pendingIntent = PendingIntent.getService(getApplicationContext(), REQUEST_CODE_NEXT, intentNext, PendingIntent.FLAG_UPDATE_CURRENT);
notificationView.setOnClickPendingIntent(R.id.notify_btn_next, pendingIntent);
//this intent and pending intent using to open the app when user click on Notification
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent notificationPendingIntent = PendingIntent.getActivity(this, NOTIFICATION_ID,
notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Intent intent = new Intent(getBaseContext(), MainActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(getApplicationContext());
stackBuilder.addNextIntent(intent);
PendingIntent pendingIntent2 = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_CANCEL_CURRENT);
mNotification = notificationCompatBuilder
.setColorized(true)
.setContent(notificationView)
/* .setContentIntent(pendingIntent2)*/ //opens activity when user click on notification
.setCustomContentView(notificationView)
.setDefaults(Notification.COLOR_DEFAULT)
.setDeleteIntent(pendingIntentStop)
.setLargeIcon(bitmapImage)
.setOngoing(true)
.setSmallIcon(R.drawable.play_logo)
.setStyle(new NotificationCompat.DecoratedCustomViewStyle())
.build();
startForeground(NOTIFICATION_ID, mNotification);
}
private void initChannel() {
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
notificationChannel = new NotificationChannel(CHANNEL_ID,
CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH);
notificationChannel.setVibrationPattern(new long[]{0});
notificationChannel.setDescription("BeatBox Notification");
notificationChannel.enableLights(false);
notificationChannel.enableVibration(false);
notificationChannel.canShowBadge();
notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
notificationManager.createNotificationChannel(notificationChannel);
}
}
private void initNoisyReceiver() {
//Handles headphones coming unplugged. cannot be done through a manifest receiver
IntentFilter filter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
registerReceiver(mNoisyReceiver, filter);
}
private BroadcastReceiver mNoisyReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (mPlayer != null && mPlayer.isPlaying()) {
mPlayer.pause();
}
}
};
private boolean successfullyRetrievedAudioFocus() {
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
int result = audioManager.requestAudioFocus(this,
AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
return result == AudioManager.AUDIOFOCUS_GAIN;
}
@Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(mNoisyReceiver);
notificationManager.cancel(NOTIFICATION_ID);
}
@Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
notificationManager.cancel(NOTIFICATION_ID);
if (mPlayer != null) {
mPlayer.stop();
mPlayer.release();
}
}
答案 0 :(得分:1)
您可以使用标记来降低系统杀死您的服务的可能性,但它永远不会是100%。但是,您可以使您的服务能够从持久性存储(如db或共享首选项)中获取播放列表本身。
答案 1 :(得分:0)
如果null Intent是唯一的问题,只需返回START_REDELIVER_INTENT
即可@Override
public int onStartCommand(Intent intent, int flags, int startId) {
.....
return START_REDELIVER_INTENT;
}
从onStartCommand(Intent, int, int)返回的常量:如果此服务的进程在启动时被终止(从onStartCommand(Intent, int, int)返回后),那么它将被安排重新启动并且最后一次传递意图通过onStartCommand(Intent, int, int)重新发送给它。