android - 在启动服务后的某个时间,列表在 Android 服务中变为空

标签 android service android-mediaplayer media

我正在开发安卓 MusicPlayer。我创建了扩展服务的服务类。在我的 Main_activity 中,我使用 startService() 方法调用服务类,同时使用 Intent.

传递音乐 list
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();
    }
}

最佳答案

您可以使用标志来降低您的服务被系统终止的可能性,但它永远不会是 100%。但是,您可以让您的服务能够从持久性存储(例如数据库或共享首选项)中获取播放列表本身。

关于android - 在启动服务后的某个时间,列表在 Android 服务中变为空,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46558457/

相关文章:

android - Android MediaPlayer的问题

android - 集成自定义解码器在android上播放同时显示fps

java - 编码差异 UTF-8 Android 4.2.2 <=> Windows 7

android - 无法从应用程序类向 Android 服务广播 Intent

android - 仅纵向模式下的屏幕高度?

android - 将广播 Intent 从服务发送到应用程序类

android - 是否可以在一个地方托管 aidl 文件?

android - Mediaplayer 在 reset() 和 prepareAsync() 调用时抛出 Error(-38,0)

android - 使用 mvvp 结构中的数据绑定(bind)导航到另一个 Activity

android - 继续检查网络连接android