如何从异步线程返回值?MediaPlayer迁移到Executor后返回报错如何解决
问题原因
- 你使用
Executor.execute()提交的是Runnable类型任务,该接口的run方法没有返回值,所以不能在内部直接return布尔值,才会触发Unexpected return value报错;同时主线程的playFile方法没有对应返回语句,自然触发Missing return statement报错。 - 你用
AtomicReference还是拿不到正确值的核心原因是:异步任务提交后主线程不会等待任务执行完成,直接读取了初始值false,此时异步任务还没完成变量赋值操作。
解决方案
方案1:用Callable+Future同步获取结果(会阻塞调用线程)
如果调用playFile的线程允许阻塞,可以用submit方法提交Callable类型任务,通过Future.get()阻塞等待任务执行完成拿到返回值:
public boolean playFile(String path) { ExecutorService executor = Executors.newSingleThreadExecutor(); Callable<Boolean> playTask = () -> { MediaPlayer mp = new MediaPlayer(); mp.setAudioAttributes(AudioFocusManager.getPlaybackAttributes()); try { mp.setDataSource(path); mp.prepare(); mp.start(); mp.setOnErrorListener((mp1, what, extra) -> true); mp.setOnCompletionListener(mp1 -> {}); return true; } catch (Exception e) { AudioFocusManager.releaseAudioFocus(); return false; } }; Future<Boolean> future = executor.submit(playTask); try { // 阻塞等待异步任务执行完成,拿到返回结果 return future.get(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); return false; } finally { // 如果是全局复用的线程池不要执行shutdown,根据业务调整 executor.shutdown(); } }
注意:不要在主线程/UI线程使用该方案,否则会造成界面卡顿甚至ANR。
方案2:异步回调(不阻塞调用线程,推荐Android等UI场景使用)
如果不能阻塞调用线程,就不要让playFile同步返回结果,改成任务执行完成后通过回调返回结果:
首先自定义回调接口:
public interface PlayCallback { void onPlayResult(boolean isSuccess); }
修改playFile方法:
public void playFile(String path, PlayCallback callback) { ExecutorService executor = Executors.newSingleThreadExecutor(); executor.execute(() -> { boolean playResult = false; MediaPlayer mp = new MediaPlayer(); mp.setAudioAttributes(AudioFocusManager.getPlaybackAttributes()); try { mp.setDataSource(path); mp.prepare(); mp.start(); mp.setOnErrorListener((mp1, what, extra) -> true); mp.setOnCompletionListener(mp1 -> {}); playResult = true; } catch (Exception e) { AudioFocusManager.releaseAudioFocus(); playResult = false; } finally { // 如果需要回调在主线程执行,可以通过主线程Handler转发回调 if (callback != null) { callback.onPlayResult(playResult); } executor.shutdown(); } }); }
调用示例:
playFile("/sdcard/test.mp3", isSuccess -> { // 在这里处理播放结果逻辑 if (isSuccess) { // 播放成功 } else { // 播放失败 } });
内容的提问来源于stack exchange,提问作者bellotas
相关产品推荐
相关产品推荐

