the_dani
the_dani

Reputation: 2524

How to play music, if app is closed

I want to build an Music-App and my Musicplayer should only stop, if the User touchs on Stop in the notification.

The Music should not stop if the User closes the App (if possible, also if the User cleans the App-History)!

I'm playing music with a Service:

public class MusicService extends Service
    implements MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener,
        AudioManager.OnAudioFocusChangeListener {

//region Variables

private MediaPlayer mediaPlayer;
private Song[] sSongs;
private int iSongPosition;

private PlayMode playMode;

private static final int NOTIFY_ID = 1;

private final IBinder musicBinder = new MusicBinder();

private AudioManager audioManager;

private Handler handler;

public ServiceInterface serviceInterface;

private Notification notification;

//endregion

//region Service-Methods

@Override
public void onCreate() {
    super.onCreate();

    mediaPlayer = new MediaPlayer();

    iSongPosition = 0;
    playMode = PlayMode.PASS;

    mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
    mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);

    mediaPlayer.setOnPreparedListener(this);
    mediaPlayer.setOnCompletionListener(this);
    mediaPlayer.setOnErrorListener(this);

    audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);

    int iAudioReqResult = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);

    if (iAudioReqResult != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
        new AlertDialog.Builder(this)
                .setTitle("Sorry.")
                .setMessage("Musixs wasn't able to gain the AudioStream garanted!")
                .setCancelable(false)
                .show();
    }

    handler = new Handler();

    serviceInterface = new ServiceInterface() {

        @Override
        public void MP_PlayPause() {
            if (isPlaying()) {
                pause();
            }
            else {
                start();
            }
        }

        @Override
        public void MP_PlayPrev() {
            playPrev();
        }

        @Override
        public void MP_PlayNext() {
            playNext();
        }

        @Override
        public boolean MP_isPlaying() {
            return isPlaying();
        }

        @Override
        public int MP_getDuration() {
            return getDuration();
        }

        @Override
        public int MP_getCurrentPosition() {
            return getCurrentPosition();
        }

        @Override
        public Song MP_getActualSong() {
            return getActualSong();
        }

        @Override
        public void MP_seekTo(int pos) {
            seekTo(pos);
        }
    };
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
    return musicBinder;
}

@Override
public boolean onUnbind(Intent intent) {
    mediaPlayer.stop();
    mediaPlayer.release();

    return super.onUnbind(intent);
}

@Override
public void onCompletion(MediaPlayer mp) {
    mp.reset();

    if (playMode == PlayMode.REPEAT_SINGLE) {
        playSong(iSongPosition);

        return;
    }

    if (playMode == PlayMode.SHUFFLE) {
        iSongPosition = new Random().nextInt(sSongs.length);

        playSong(iSongPosition);

        return;
    }

    iSongPosition++;

    if (iSongPosition == sSongs.length) {
        if (playMode == PlayMode.REPEAT_ALL) {
            iSongPosition = 0;

            playSong(iSongPosition);
        }
        else {
            mp.stop();
            mp.release();
        }
    }
    else {
        playSong(iSongPosition);
    }
}

@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
    mp.reset();

    return false;
}

@Override
public void onPrepared(MediaPlayer mp) {
    mp.start();

    Intent notIntent = new Intent(getApplicationContext(), PlayActivity.class);
    notIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

    PendingIntent notPendignIntent = PendingIntent.getActivity(getApplicationContext(), 0, notIntent, PendingIntent.FLAG_UPDATE_CURRENT);

    PlayActivity.setServiceInterface(serviceInterface);

    Notification.Builder nBuilder = new Notification.Builder(this);

    nBuilder.setContentIntent(notPendignIntent)
            .setSmallIcon(android.R.drawable.ic_media_play)
            .setTicker(getActualSong().getTitle())
            .setOngoing(true)
            .setContentTitle(getString(R.string.app_name))
            .setContentText(getActualSong().getTitle());

    notification = nBuilder.build();

    startForeground(NOTIFY_ID, notification);
}

@Override
public void onDestroy() {
    super.onDestroy();

    stopForeground(true);
}

@Override
public void onAudioFocusChange(int focusChange) {
    audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
}

//endregion

//region Methods

public void setSongs(Song[] songs) {
    sSongs = songs;
}

public void setPlayMode(PlayMode mode) {
    playMode = mode;
}

public void playSong(int index) {
    mediaPlayer.reset();

    iSongPosition = index;

    Song playSong = sSongs[iSongPosition];

    long playSongID = playSong.getID();

    Uri trackUri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, playSongID);

    try {
        mediaPlayer.setDataSource(getApplicationContext(), trackUri);
    }
    catch (IOException ioe) {
        ioe.printStackTrace();
    }

    mediaPlayer.prepareAsync();
}

public void playNext() {
    iSongPosition++;

    if (iSongPosition == sSongs.length) {
        iSongPosition = 0;
    }

    playSong(iSongPosition);
}

public void playPrev() {
    iSongPosition--;

    if (iSongPosition < 0) {
        iSongPosition = sSongs.length - 1;
    }

    playSong(iSongPosition);
}

public Song getActualSong() {
    return sSongs[iSongPosition];
}

public int getActualSongPosition() {
    return iSongPosition;
}

public PlayMode getPlayMode() {
    return playMode;
}

//region MediaController-Methods

public void start() {
    mediaPlayer.start();

    startForeground(NOTIFY_ID, notification);
}

public void pause() {
    mediaPlayer.pause();

    stopForeground(true);
}

public int getDuration() {
    return mediaPlayer.getDuration();
}

public int getCurrentPosition() {
    return mediaPlayer.getCurrentPosition();
}

public void seekTo(int pos) {
    mediaPlayer.seekTo(pos);
}

public boolean isPlaying() {
    return mediaPlayer.isPlaying();
}

public int getBufferPercentage() {
    return (mediaPlayer.getCurrentPosition() * 100) / mediaPlayer.getDuration();
}

public boolean canPause() {
    return mediaPlayer.isPlaying();
}

public boolean canSeekBackward() {
    return mediaPlayer.getCurrentPosition() != 0;
}

public boolean canSeekForward() {
    return mediaPlayer.getCurrentPosition() == mediaPlayer.getDuration();
}

//endregion

//endregion

public class MusicBinder extends Binder {
    public MusicService getService() {
        return MusicService.this;
    }
}

And my Service is started in MainActivity:

@Override
protected void onStart() {
    super.onStart();

    if (playIntent == null) {
        playIntent = new Intent(this, MusicService.class);

        bindService(playIntent, musicServiceConn, BIND_AUTO_CREATE);

        startService(playIntent);
    }
}

My ServiceConnection:

musicServiceConn = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        MusicService.MusicBinder musicBinder = (MusicService.MusicBinder) service;

        musicService = musicBinder.getService();

        bMusicServiceConnected = true;

        musicService.setSongs(sSongs);
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        bMusicServiceConnected = false;
    }
};

Actually, my MediaPlayer stops, if I close the app (clear App-History) or press the Back-Button.

The full code: https://github.com/guger/Musixs

I hope you can help me! Thanks!

Upvotes: 0

Views: 119

Answers (1)

F43nd1r
F43nd1r

Reputation: 7749

You need to override onStartCommand in the service and return START_STICKY.

Upvotes: 1

Related Questions