Я получаю исключение IllegalState из MediaPlayer в корутине и не понимаю, почему.

Вопрос или проблема

Мое приложение — это симулятор, который показывает мышь, бегущую по экрану с периодическими 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 до завершения прошлых операций или после его освобождения. Давайте проанализируем ваш код и внесем необходимые исправления.

  1. Управление состоянием MediaPlayer: Убедитесь, что вы правильно управляете состоянием MediaPlayer. Перед вызовом start(), проверьте, что объект currentMediaPlayer был успешно инициализирован, а также что он не был освобожден.

  2. Добавление обработки исключений: Включите обработку исключений, чтобы можно было отловить и диагностировать проблемы с MediaPlayer.

  3. Асинхронность: Использование 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")
    }
}

Основные изменения:

  1. when инициализация: Я использовал when с инициализацией MediaPlayer. Если звук не распознан, медиаплеер останется null.
  2. let: Мы проверяем и работаем с currentMediaPlayer через let, что обеспечит отсутствие NullPointerException.
  3. runBlocking { delay(metaD) }: Используйте delay() из библиотеки корутин вместо Thread.sleep().
  4. Обработка исключений: Добавляйте обработку исключений, чтобы легче управлять потенциальными ошибками.

Теперь ваш код не должен выбрасывать IllegalStateException, и выполнение звука не будет блокировать основной поток приложения.

Оцените материал
Добавить комментарий

Капча загружается...