Fixed concurrency problems

This commit is contained in:
Nite 2020-06-26 13:31:31 +02:00
parent b83631107c
commit 0bef3ae417
No known key found for this signature in database
GPG Key ID: 1D1AD59B1C6386C1
2 changed files with 62 additions and 54 deletions

View File

@ -92,19 +92,6 @@ public class MediaPlayerControllerImpl implements MediaPlayerController
Log.i(TAG, "MediaPlayerControllerImpl destroyed"); Log.i(TAG, "MediaPlayerControllerImpl destroyed");
} }
private void executeOnStartedMediaPlayerService(final Consumer<MediaPlayerService> taskToExecute)
{
Thread t = new Thread()
{
public void run()
{
MediaPlayerService instance = MediaPlayerService.getInstance(context);
taskToExecute.accept(instance);
}
};
t.start();
}
@Override @Override
public synchronized void restore(List<MusicDirectory.Entry> songs, final int currentPlayingIndex, final int currentPlayingPosition, final boolean autoPlay, boolean newPlaylist) public synchronized void restore(List<MusicDirectory.Entry> songs, final int currentPlayingIndex, final int currentPlayingPosition, final boolean autoPlay, boolean newPlaylist)
{ {
@ -112,7 +99,7 @@ public class MediaPlayerControllerImpl implements MediaPlayerController
if (currentPlayingIndex != -1) if (currentPlayingIndex != -1)
{ {
executeOnStartedMediaPlayerService(new Consumer<MediaPlayerService>() { MediaPlayerService.executeOnStartedMediaPlayerService(context, new Consumer<MediaPlayerService>() {
@Override @Override
public void accept(MediaPlayerService mediaPlayerService) { public void accept(MediaPlayerService mediaPlayerService) {
mediaPlayerService.play(currentPlayingIndex, autoPlayStart); mediaPlayerService.play(currentPlayingIndex, autoPlayStart);
@ -129,7 +116,7 @@ public class MediaPlayerControllerImpl implements MediaPlayerController
{ {
if (localMediaPlayer.currentPlaying.isCompleteFileAvailable()) if (localMediaPlayer.currentPlaying.isCompleteFileAvailable())
{ {
executeOnStartedMediaPlayerService(new Consumer<MediaPlayerService>() { MediaPlayerService.executeOnStartedMediaPlayerService(context, new Consumer<MediaPlayerService>() {
@Override @Override
public void accept(MediaPlayerService mediaPlayerService) { public void accept(MediaPlayerService mediaPlayerService) {
localMediaPlayer.doPlay(localMediaPlayer.currentPlaying, currentPlayingPosition, autoPlay); localMediaPlayer.doPlay(localMediaPlayer.currentPlaying, currentPlayingPosition, autoPlay);
@ -145,7 +132,7 @@ public class MediaPlayerControllerImpl implements MediaPlayerController
@Override @Override
public synchronized void play(final int index) public synchronized void play(final int index)
{ {
executeOnStartedMediaPlayerService(new Consumer<MediaPlayerService>() { MediaPlayerService.executeOnStartedMediaPlayerService(context,new Consumer<MediaPlayerService>() {
@Override @Override
public void accept(MediaPlayerService mediaPlayerService) { public void accept(MediaPlayerService mediaPlayerService) {
mediaPlayerService.play(index, true); mediaPlayerService.play(index, true);
@ -155,7 +142,7 @@ public class MediaPlayerControllerImpl implements MediaPlayerController
public synchronized void play() public synchronized void play()
{ {
executeOnStartedMediaPlayerService(new Consumer<MediaPlayerService>() { MediaPlayerService.executeOnStartedMediaPlayerService(context, new Consumer<MediaPlayerService>() {
@Override @Override
public void accept(MediaPlayerService mediaPlayerService) { public void accept(MediaPlayerService mediaPlayerService) {
mediaPlayerService.play(); mediaPlayerService.play();
@ -167,7 +154,7 @@ public class MediaPlayerControllerImpl implements MediaPlayerController
public synchronized void togglePlayPause() public synchronized void togglePlayPause()
{ {
if (localMediaPlayer.playerState == PlayerState.IDLE) autoPlayStart = true; if (localMediaPlayer.playerState == PlayerState.IDLE) autoPlayStart = true;
executeOnStartedMediaPlayerService(new Consumer<MediaPlayerService>() { MediaPlayerService.executeOnStartedMediaPlayerService(context,new Consumer<MediaPlayerService>() {
@Override @Override
public void accept(MediaPlayerService mediaPlayerService) { public void accept(MediaPlayerService mediaPlayerService) {
mediaPlayerService.togglePlayPause(); mediaPlayerService.togglePlayPause();
@ -178,7 +165,7 @@ public class MediaPlayerControllerImpl implements MediaPlayerController
@Override @Override
public synchronized void seekTo(final int position) public synchronized void seekTo(final int position)
{ {
executeOnStartedMediaPlayerService(new Consumer<MediaPlayerService>() { MediaPlayerService.executeOnStartedMediaPlayerService(context, new Consumer<MediaPlayerService>() {
@Override @Override
public void accept(MediaPlayerService mediaPlayerService) { public void accept(MediaPlayerService mediaPlayerService) {
mediaPlayerService.seekTo(position); mediaPlayerService.seekTo(position);
@ -189,7 +176,7 @@ public class MediaPlayerControllerImpl implements MediaPlayerController
@Override @Override
public synchronized void pause() public synchronized void pause()
{ {
executeOnStartedMediaPlayerService(new Consumer<MediaPlayerService>() { MediaPlayerService.executeOnStartedMediaPlayerService(context, new Consumer<MediaPlayerService>() {
@Override @Override
public void accept(MediaPlayerService mediaPlayerService) { public void accept(MediaPlayerService mediaPlayerService) {
mediaPlayerService.pause(); mediaPlayerService.pause();
@ -200,7 +187,7 @@ public class MediaPlayerControllerImpl implements MediaPlayerController
@Override @Override
public synchronized void start() public synchronized void start()
{ {
executeOnStartedMediaPlayerService(new Consumer<MediaPlayerService>() { MediaPlayerService.executeOnStartedMediaPlayerService(context, new Consumer<MediaPlayerService>() {
@Override @Override
public void accept(MediaPlayerService mediaPlayerService) { public void accept(MediaPlayerService mediaPlayerService) {
mediaPlayerService.start(); mediaPlayerService.start();
@ -211,7 +198,7 @@ public class MediaPlayerControllerImpl implements MediaPlayerController
@Override @Override
public synchronized void stop() public synchronized void stop()
{ {
executeOnStartedMediaPlayerService(new Consumer<MediaPlayerService>() { MediaPlayerService.executeOnStartedMediaPlayerService(context, new Consumer<MediaPlayerService>() {
@Override @Override
public void accept(MediaPlayerService mediaPlayerService) { public void accept(MediaPlayerService mediaPlayerService) {
mediaPlayerService.stop(); mediaPlayerService.stop();

View File

@ -55,6 +55,7 @@ public class MediaPlayerService extends Service
private static final int NOTIFICATION_ID = 3033; private static final int NOTIFICATION_ID = 3033;
private static MediaPlayerService instance = null; private static MediaPlayerService instance = null;
private static final Object instanceLock = new Object();
private final IBinder binder = new SimpleServiceBinder<>(this); private final IBinder binder = new SimpleServiceBinder<>(this);
private final Scrobbler scrobbler = new Scrobbler(); private final Scrobbler scrobbler = new Scrobbler();
@ -75,28 +76,42 @@ public class MediaPlayerService extends Service
public static MediaPlayerService getInstance(Context context) public static MediaPlayerService getInstance(Context context)
{ {
for (int i = 0; i < 5; i++) synchronized (instanceLock) {
{ for (int i = 0; i < 5; i++) {
if (instance != null) return instance; if (instance != null) return instance;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
{ context.startForegroundService(new Intent(context, MediaPlayerService.class));
context.startForegroundService(new Intent(context, MediaPlayerService.class)); } else {
} context.startService(new Intent(context, MediaPlayerService.class));
else }
{
context.startService(new Intent(context, MediaPlayerService.class)); Util.sleepQuietly(50L);
} }
Util.sleepQuietly(50L); return instance;
} }
return instance;
} }
public static MediaPlayerService getRunningInstance() public static MediaPlayerService getRunningInstance()
{ {
return instance; synchronized (instanceLock)
{
return instance;
}
}
public static void executeOnStartedMediaPlayerService(final Context context, final Consumer<MediaPlayerService> taskToExecute)
{
Thread t = new Thread()
{
public void run()
{
MediaPlayerService instance = getInstance(context);
taskToExecute.accept(instance);
}
};
t.start();
} }
@Nullable @Nullable
@ -169,19 +184,25 @@ public class MediaPlayerService extends Service
instance = null; instance = null;
try try {
{
localMediaPlayer.onDestroy(); localMediaPlayer.onDestroy();
shufflePlayBuffer.onDestroy(); shufflePlayBuffer.onDestroy();
downloader.onDestroy(); downloader.onDestroy();
} } catch (Throwable ignored) {
catch (Throwable ignored)
{
} }
Log.i(TAG, "MediaPlayerService stopped"); Log.i(TAG, "MediaPlayerService stopped");
} }
private void stopIfIdle()
{
synchronized (instanceLock)
{
// currentPlaying could be changed from another thread in the meantime, so check again before stopping for good
if (localMediaPlayer.currentPlaying == null) stopSelf();
}
}
public synchronized void seekTo(int position) public synchronized void seekTo(int position)
{ {
if (jukeboxMediaPlayer.getValue().isEnabled()) if (jukeboxMediaPlayer.getValue().isEnabled())
@ -252,8 +273,8 @@ public class MediaPlayerService extends Service
if (currentPlaying != null) if (currentPlaying != null)
{ {
updateNotification(localMediaPlayer.playerState, currentPlaying);
if (tabInstance != null) { if (tabInstance != null) {
updateNotification(localMediaPlayer.playerState, currentPlaying);
tabInstance.showNowPlaying(); tabInstance.showNowPlaying();
} }
} }
@ -262,11 +283,11 @@ public class MediaPlayerService extends Service
if (tabInstance != null) if (tabInstance != null)
{ {
tabInstance.hideNowPlaying(); tabInstance.hideNowPlaying();
stopForeground(true);
localMediaPlayer.clearRemoteControl();
isInForeground = false;
stopSelf();
} }
stopForeground(true);
localMediaPlayer.clearRemoteControl();
isInForeground = false;
stopIfIdle();
} }
} }
}; };
@ -457,12 +478,12 @@ public class MediaPlayerService extends Service
if (show) if (show)
{ {
if (tabInstance != null) // Only update notification if localMediaPlayer state is one that will change the icon
if (playerState == PlayerState.STARTED || playerState == PlayerState.PAUSED)
{ {
// Only update notification is localMediaPlayer state is one that will change the icon updateNotification(playerState, currentPlaying);
if (playerState == PlayerState.STARTED || playerState == PlayerState.PAUSED) if (tabInstance != null)
{ {
updateNotification(playerState, currentPlaying);
tabInstance.showNowPlaying(); tabInstance.showNowPlaying();
} }
} }
@ -471,12 +492,12 @@ public class MediaPlayerService extends Service
{ {
if (tabInstance != null) if (tabInstance != null)
{ {
stopForeground(true);
localMediaPlayer.clearRemoteControl();
isInForeground = false;
tabInstance.hideNowPlaying(); tabInstance.hideNowPlaying();
stopSelf();
} }
stopForeground(true);
localMediaPlayer.clearRemoteControl();
isInForeground = false;
stopIfIdle();
} }
if (playerState == STARTED) if (playerState == STARTED)