如何 return 来自异步线程的值
How to return a value from a async thread
我正在开发 MediaPlayer
来播放音频文件
目前在主线程上工作
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;
}
}
但我正在尝试将其移至执行程序
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(() -> {
});
一旦我将其移至执行程序,第二个和第三个 returns 就会触发错误
Unexpected return value
并且playFile
触发以下
Missing return statement
我试过使用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();
但它总是触发false,意味着它不等待线程更新它
我该怎么做?
execute 方法需要一个 Runnable 而 Runnable 不需要 return 任何东西,这就是为什么你会得到意外的 return 值错误。
您不能像这样直接从单独的线程获取播放文件的 return 值,但是您使用 AtomicReference 的方法应该有效。
布尔值有一个内置的原子类型 AtomicBoolean,请考虑改用它。
尝试改变这个:
mp.setOnErrorListener((mp1, what, extra) -> {
return true;
});
为此:
mp.setOnErrorListener((mp1, what, extra) -> {
correctlyPlayed.set(true);
});
此外,您可能希望在 returning 之前同步您的代码以等待其他线程执行,为此,请考虑检查一些信号量同步技术(例如 CountdownLatch),我建议您阅读也了解等待通知机制。正如您正确指出的那样,始终将 return 值设为 false 的原因很可能是同步问题。
如评论所说,用executor#submit
代替executor#execute
,这样就可以得到一个Future
,调用Future#get
得到结果:
Future<Boolean> future = executor.submit(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
// ...
return true;
}
});
return future.get(); // block until get result
我正在开发 MediaPlayer
来播放音频文件
目前在主线程上工作
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;
}
}
但我正在尝试将其移至执行程序
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(() -> {
});
一旦我将其移至执行程序,第二个和第三个 returns 就会触发错误
Unexpected return value
并且playFile
触发以下
Missing return statement
我试过使用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();
但它总是触发false,意味着它不等待线程更新它
我该怎么做?
execute 方法需要一个 Runnable 而 Runnable 不需要 return 任何东西,这就是为什么你会得到意外的 return 值错误。 您不能像这样直接从单独的线程获取播放文件的 return 值,但是您使用 AtomicReference 的方法应该有效。 布尔值有一个内置的原子类型 AtomicBoolean,请考虑改用它。
尝试改变这个:
mp.setOnErrorListener((mp1, what, extra) -> {
return true;
});
为此:
mp.setOnErrorListener((mp1, what, extra) -> {
correctlyPlayed.set(true);
});
此外,您可能希望在 returning 之前同步您的代码以等待其他线程执行,为此,请考虑检查一些信号量同步技术(例如 CountdownLatch),我建议您阅读也了解等待通知机制。正如您正确指出的那样,始终将 return 值设为 false 的原因很可能是同步问题。
如评论所说,用executor#submit
代替executor#execute
,这样就可以得到一个Future
,调用Future#get
得到结果:
Future<Boolean> future = executor.submit(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
// ...
return true;
}
});
return future.get(); // block until get result