Я работаю над 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(() -> {

    });

Как только я перемещаю его к исполнителю, второй и третий возврат вызывает ошибку

Неожиданное возвращаемое значение

И playFile запускает следующее

Отсутствует оператор возврата

Я пробовал использовать 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, что означает, что он не ждет, пока поток обновит его

Как я мог это сделать?

0
bellotas 26 Ноя 2021 в 13:51
Что является точным исключением, когда вы бежите второй и третий раз? Можете ли вы опубликовать это исключение и сообщение? Если это просто «медиа-файл используется» или что-то в этом роде, то это не проблема, связанная с Java. Давайте сначала проясним это.
 – 
Sree Kumar
26 Ноя 2021 в 14:16
Вы должны использовать submit вместо execute, поскольку он возвращает Future, с помощью которого вы можете управлять задачей.
 – 
MC Emperor
26 Ноя 2021 в 14:20

2 ответа

Лучший ответ

Как сказано в комментарии, используйте 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
2
zysaaa 26 Ноя 2021 в 14:47

Для метода execute требуется Runnable, а Runnable ничего не возвращает, поэтому вы получаете неожиданную ошибку возвращаемого значения. Вы не можете напрямую получить возвращаемое значение вашего playFile из отдельного потока, но ваш подход с AtomicReference должен работать. Существует встроенный атомарный тип для логических значений, AtomicBoolean, рассмотрите возможность его использования.

Попробуйте изменить это:

mp.setOnErrorListener((mp1, what, extra) -> {
    return true;
});

К этому:

mp.setOnErrorListener((mp1, what, extra) -> {
    correctlyPlayed.set(true);
});

Кроме того, вы можете захотеть синхронизировать свой код, чтобы дождаться выполнения другого потока перед возвратом, для этого рассмотрите возможность проверки некоторых методов синхронизации семафоров (например, CountdownLatch), и я предлагаю вам также прочитать о механизме ожидания-уведомления. Причина, по которой всегда возвращается значение false в качестве возвращаемого значения, скорее всего, является проблемой синхронизации, как вы правильно указали.

1
Toni Nagy 26 Ноя 2021 в 14:17