Вопрос или проблема
Мое приложение — это симулятор, который показывает мышь, бегущую по экрану с периодическими squeaks в случайные интервалы, чтобы привлечь внимание кошек. Я получаю исключение IllegalState в однопоточном корутином. Вся активность MediaPlayer происходит в этом потоке, поэтому я не понимаю ошибку, которая возникает в строке, где я проверяю, воспроизводит ли медиаплеер звук. Он работает, если я не использую корутину, но вызывает задержку в основном потоке, что мешает функции обновления и останавливает мышь.
CoroutineScope(newSingleThreadContext("PlaySound")).launch{PlaySound(0)}
private fun PlaySound(sound: Int) {
when(sound){
0 -> currentMediaPlayer = MediaPlayer.create(gameContext,R.raw.mouse_squeak)
1 -> currentMediaPlayer = MediaPlayer.create(gameContext,R.raw.mouse_squeaking1)
2 -> currentMediaPlayer = MediaPlayer.create(gameContext,R.raw.mouse_squeaking2)
3 -> currentMediaPlayer = MediaPlayer.create(gameContext,R.raw.mouse_squeaking3)
4 -> currentMediaPlayer = MediaPlayer.create(gameContext,R.raw.mouse_squeaking4)
5 -> currentMediaPlayer = MediaPlayer.create(gameContext,R.raw.mouse_squeaking5)
6 -> currentMediaPlayer = MediaPlayer.create(gameContext,R.raw.mouse_squeaking6)
7 -> currentMediaPlayer = MediaPlayer.create(gameContext,R.raw.mouse_squeaking7)
8 -> currentMediaPlayer = MediaPlayer.create(gameContext,R.raw.mouse_squeaking8)
9 -> currentMediaPlayer = MediaPlayer.create(gameContext,R.raw.mouse_squeaking9)
10 -> currentMediaPlayer = MediaPlayer.create(gameContext,R.raw.mouse_squeaking10)
11 -> currentMediaPlayer = MediaPlayer.create(gameContext,R.raw.mouse_squeaking10)
}
currentMediaPlayer.start()
var metaD = ((currentMediaPlayer.duration.toLong()) * 0.8).toLong()
Thread.sleep(metaD)
if (currentMediaPlayer.isPlaying) {
currentMediaPlayer.stop()
}
currentMediaPlayer.reset()
currentMediaPlayer.release()
}
Ошибка в logcat:
E FATAL EXCEPTION: PlaySound Процесс: info.mstitservices.mouse4cat, PID: 11539 java.lang.IllegalStateException
at android.media.MediaPlayer.isPlaying(Нативный метод) at info.mstitservices.mouse4cat.Game.PlaySound(Game.kt:873)
at info.mstitservices.mouse4cat.Game.access$PlaySound(Game.kt:31) at info.mstitservices.mouse4cat.Game$MouseSqueaks$1.invokeSuspend(Game.kt:664)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:462)
at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923) Подавлено: kotlinx.coroutines.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@9679fd3, java.util.concurrent.ScheduledThreadPoolExecutor@4038710[Работающий, размер пула = 1, активные потоки = 1, очередь задач = 0, завершенные задачи = 0]]
Если я запускаю PlaySound как обычную функцию, она работает, но задерживает основной поток, вызывая остановку движения мыши. Есть ли другой способ вызвать корутину, который мне следует использовать?
Ответ или решение
Проблема с получением исключения IllegalStateException
от MediaPlayer
в вашем коде связана с тем, что вы пытаетесь обратиться к методам медиаплеера в состоянии, когда он не готов к выполнению этих операций. Это может происходить, если вы попытаетесь вызвать методы MediaPlayer
до завершения прошлых операций или после его освобождения. Давайте проанализируем ваш код и внесем необходимые исправления.
-
Управление состоянием MediaPlayer: Убедитесь, что вы правильно управляете состоянием
MediaPlayer
. Перед вызовомstart()
, проверьте, что объектcurrentMediaPlayer
был успешно инициализирован, а также что он не был освобожден. -
Добавление обработки исключений: Включите обработку исключений, чтобы можно было отловить и диагностировать проблемы с
MediaPlayer
. -
Асинхронность: Использование
Thread.sleep()
блокирует поток, но в корутинах лучше использовать механизмы ожидания, такие какdelay()
, чтобы обеспечить не блокирующее выполнение.
Вот переписанный вариант вашего метода PlaySound
, который учитывает все вышеперечисленные рекомендации:
private fun PlaySound(sound: Int) {
// Инициализация MediaPlayer
currentMediaPlayer = when (sound) {
0 -> MediaPlayer.create(gameContext, R.raw.mouse_squeak)
1 -> MediaPlayer.create(gameContext, R.raw.mouse_squeaking1)
2 -> MediaPlayer.create(gameContext, R.raw.mouse_squeaking2)
3 -> MediaPlayer.create(gameContext, R.raw.mouse_squeaking3)
4 -> MediaPlayer.create(gameContext, R.raw.mouse_squeaking4)
5 -> MediaPlayer.create(gameContext, R.raw.mouse_squeaking5)
6 -> MediaPlayer.create(gameContext, R.raw.mouse_squeaking6)
7 -> MediaPlayer.create(gameContext, R.raw.mouse_squeaking7)
8 -> MediaPlayer.create(gameContext, R.raw.mouse_squeaking8)
9 -> MediaPlayer.create(gameContext, R.raw.mouse_squeaking9)
10 -> MediaPlayer.create(gameContext, R.raw.mouse_squeaking10)
11 -> MediaPlayer.create(gameContext, R.raw.mouse_squeaking10)
else -> null
}
currentMediaPlayer?.let { player ->
try {
player.start()
val metaD = (player.duration * 0.8).toLong()
// Вместо Thread.sleep используем delay для корутины
runBlocking { delay(metaD) }
if (player.isPlaying) {
player.stop()
}
} catch (e: IllegalStateException) {
// Логирование или обработка исключения
Log.e("MediaPlayerError", "Ошибка MediaPlayer: ${e.message}")
} finally {
player.reset()
player.release()
}
} ?: run {
Log.e("MediaPlayerError", "Ошибка инициализации MediaPlayer")
}
}
Основные изменения:
when
инициализация: Я использовалwhen
с инициализациейMediaPlayer
. Если звук не распознан, медиаплеер останетсяnull
.let
: Мы проверяем и работаем сcurrentMediaPlayer
черезlet
, что обеспечит отсутствиеNullPointerException
.runBlocking { delay(metaD) }
: Используйтеdelay()
из библиотеки корутин вместоThread.sleep()
.- Обработка исключений: Добавляйте обработку исключений, чтобы легче управлять потенциальными ошибками.
Теперь ваш код не должен выбрасывать IllegalStateException
, и выполнение звука не будет блокировать основной поток приложения.