I am working on a MediaPlayer
to play an audio file
Currently works on the main thread
public boolean playFile(String path) {
MediaPlayer mp = new MediaPlayer();
mp.setAudioAttributes(AudioFocusManager.getPlaybackAttributes());
try {
mp.setDataSource(path);
mp.prepare();
mp.start();
mp.setOnErrorListener((mp1, what, extra) -> {
return true;
});
mp.setOnCompletionListener( mp1 -> {
});
return true;
} catch (Exception e) {
return false;
}
}
but I am trying to move it to an executor
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(() -> {
});
Once I move it to the executor, then the second and third returns triggers an error
Unexpected return value
And playFile
triggers the following
Missing return statement
I have tried using AtomicReference
AtomicReference<Boolean> correctlyPlayed = new AtomicReference<>(false);
//set up MediaPlayer
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(() -> {
MediaPlayer mp = new MediaPlayer();
mp.setAudioAttributes(AudioFocusManager.getPlaybackAttributes());
try {
mp.setDataSource(path);
mp.prepare();
mp.start();
mp.setOnErrorListener((mp1, what, extra) -> {
return true;
});
mp.setOnCompletionListener( mp1 -> {
});
correctlyPlayed.set(true);
} catch (Exception e) {
AudioFocusManager.releaseAudioFocus();
correctlyPlayed.set(false);
}
});
return correctlyPlayed.get();
but it triggers always false, meaning that it does not wait for the thread to update it
How could I do it?
CodePudding user response:
As the comment said, use executor#submit
instead of executor#execute
, so you can get a Future
, and you can call Future#get
to get the result:
Future<Boolean> future = executor.submit(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
// ...
return true;
}
});
return future.get(); // block until get result
CodePudding user response:
The execute method requires a Runnable and a Runnable does not return anything, that's why you get the unexpected return value error. You can't get your playFile's return value from a separate thread directly like this, but your approach with the AtomicReference should work. There is a built-in atomic type for boolean values, AtomicBoolean, consider using that instead.
Try changing this:
mp.setOnErrorListener((mp1, what, extra) -> {
return true;
});
To this:
mp.setOnErrorListener((mp1, what, extra) -> {
correctlyPlayed.set(true);
});
Also, you might want to synchronize your code to wait for the other thread to execute before returning, for that, consider checking out some semaphore synchronization techniques(e.g. CountdownLatch) and I suggest you to read up about the wait-notify mechanism too. The reason behind always getting false as a return value is most probably a synchronization issue, as you pointed out correctly.