2017-10-04 73 views
1

我正在開發android MusicPlayer。我創建了服務類擴展服務。從我的Main_activity我打電話給服務類使用startService()方法同時傳遞音樂列表意圖。List Service在啓動服務後的某個時間在Android Service中爲null

我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(); 
    } 
} 

回答

1

您可能可以使用標誌使服務不太可能被系統殺死,但它永遠不會100%。但是,您可以使您的服務能夠從持久性存儲(例如數據庫或共享首選項)中抓取播放列表本身。

+0

我正在使用SQLite存儲我的歌曲列表,從我的mainActivity我正在讀取該數據並使用Intent將其發送到Arraylist表單中的服務。我正在考慮只從Service讀取數據。但是,如果我的服務仍然存在,爲什麼我的列表變爲空? –

+1

我認爲系統殺死它來恢復資源,然後當你嘗試再次使用它時重新啓動它而沒有列表。 – meeeee

相關問題