Главная » Программирование игр под Android » ANDROID AUDIO, ANDROIDSOUND И ANDROID MUSIC – ВСЕ О ЗВУКЕ

0

 

Sound позволяет проигрывать звуковые эффекты, полностью хранящиеся вопс-ративной памяти, Music воспроизводит большие по размеру звуковые файлы, хранящиеся на диске. Начнем с реализации AndroidAudio так, как это показано и листинге 5,2.

Листинг 5.2. AndroidAudio.,javd. реализация аудиоинтерфейса package com.bad  ogiс:.androidqamps framework impl:

Реализация Androi dAudi о содержит AssetManager и экземпляр SoundPool. Нам нужен AssetManager для того, чтобы мы могли загрузить звуковой эффект из файлов ресурсов (assets) в SoundPool при обращении к Androi dAud i о. newSound. В свою очередь, для управления SoundPool используется экземпляр класса Androi dAudiо.

В конструкторе мы передаем Activity нашей игры, это делается по двум причинам: так мы можем установить регулятор звука медианотока (а нам это в любом случае понадобится), а также получаем AssetManager, который мы сохраняем в соответствующем члене класса. SoundPool создан таким образом, что он способен проигрывать одновременно до 20 звуковых эффектов. Этого более чем достаточно для решения стоящей перед нами задачи.

Метод newMusicO создает новый экземпляр класса AndroidMusic. Конструктор данного класса использует AssetFi leDescriptor, из которого внутрисистемно создается Medi aPl ауег (позже мы рассмотрим этот вопрос подробнее). Метод AssetManager openFd вызовет исключение IOException, если что-то пойдет не так. Мы примем это исключение и повторно выдадим его как RuntimeException. Вы спросите, почему бы не оставить 1.0. xception для того, чтобы сообщить об ошибке вызывающей стороне? Прежде всего, так работающий код станет гораздо более запутанным, так что лучше используем Runt imeL xcept ion, которое не требуется специально перехватывать. Мы загружаем музыку из файла assets. Единственный случай, когда может возникнуть сбой, если мы забудем добавить музыкальный файл в папку assets/ или если внутри нашего файла будут содержаться фиктивные байты. В такой ситуации могут возникать неисправимые ошибки, поскольку нам нужен экземпляр класса Music, чтобы паша игра правильно функционировала. Чтобы не попадать в такие ситуации, мы используем стратегию замены проверяемых исключений на Runt imeExcept ion еще в нескольких точках игрового фреймворка.

В итоге метод newSouncK) загружает звуковой эффект из assets в SoundPool и возвращает экземпляр класса AndroidSound. Конструктор данного экземпляра класса принимает SoundPool и ID звукового эффекта этот идентификатор ему присвоил SoundPool. Мы снова заменяем перехваченные исключения на Runtimel xception.

ПРИМЕЧАНИЕ

Мы не освобождаем SoundPool ни в одном из методов. Причина этого заключается в том, что у нас в любом случае будет экземпляр класса Game, содержащий один экземпляр класса Audio, который, в свою очередь, включает в себя один экземпляр класса SoundPool. SoundPool будет существовать до тех пор, пока существует игра. Он автоматически удалится, как только активность закончит работу.

Далее обсудим класс AndroidSound, который реализует интерфейс Sound (листинг 5.3).

Листинг 5.3. AndroidSound.java: Реализация интерфейса Sound package com.badlogiс.androidgames.framework.imp I:

Ничего сверхъестественного. Мы просто сохранили SoundPool и ID загруженных звуковых эффектов для их последующего воспроизведения и утилизации с помощью методов р 1 ау и disposeO. Проще не бывает. Все это благодаря удобству самого API Android.

И наконец, нам необходимо реализовать класс AndroidMusic, возвращаемый AndroidAudio.newMusic.

В листинге 5.4 приведен код для этого класса. Он выглядит немного более сложным, чем предыдущие примеры. Это объясняется применением машины состояний, которую использует MediaPlауег. Она сгенерирует кучу исключений, если мы будем вызывать методы в тех состояниях, когда этого делать не следует.

Листинг 5.4. AndroidMusic.java: реализация ишерфейса Music-package com,badlogic.androidgames.framework impl:

Класс AndroidMusic сохраняет экземпляр класса MedwiPlayer вместе с булевым значением isPrepared. Обратите внимание, мы можем использовать MediaPlayer start. )/stop( )/pause, только когда MediaPlayer готов (prepared). Этот член позволяет отслеживать состояние MediaP1ауег.

Класс AndroidMusic реализует не только интерфейс Music, но также интерфейс OnComplet ionL istener.

Пели это случится, следует заново подготовить MediaPlayer, так как до этого мы не можем вызывать никаких методов. Метод OnCompl eti onLi stener. onCompl eti on  может быть использован в другом потоке, и, поскольку мы устанавливаем член i sPrepared в данном методе, необходимо убедиться, что к нему не будут применяться противоречащие друг другу изменения.

В конструкторе создаем и готовим MediaPlауег из AssetFileDescriptor, устанавливаем флаг i sPrepared, а также регистрируем экземпляр класса Androi dMusi с в качестве слушателя (приемника) OnCompl eti onLi stener в Medi aPl ауег. Если что-то пойдет не так, будет сгенерировано непроверяемое исключение RuntimeException.

Метод di spose сначала проверяет, по-прежнему ли работает Medi aPlауег, и, если воспроизведение продолжается, останавливает его. В противном случае обращение KMediaPlayer.releaseO вызовет исключение времени выполнения.

Методы isLoopingO, isPlayingO и isStoppedO довольно просты. Первые два используют методы, предоставленные Medi aPlауег; последний применяет флаг 3 sPrepared, который показывает, что Medi аР1ауег остановлен. Например, Medi aPl ауег. isPlayingO не может предоставить нам точную информацию по этому вопросу, так как он не различает, остановлен Medi аРlayer или же просто поставлен на паузу.

Теперь к работе подключается метод piау. Если воспроизведение уже идет, то просто выполняем возврат из функции. Далее используем универсальный блок try… catch, который сначала проверяет, готов ли Medi aPlауег (это можно узнать по значению флага), и подготавливает его, если это требуется. Если ошибок нет, обращаемся к методу MediaPlауег.start, который воспроизводит музыку. Все это делается в синхронизированном блоке, поскольку мы используем флаг  sPrepared, который благодаря интерфейсу OnCompl eti onLi stener может быть установлен в отдельном потоке. Если возникнут какие-то проблемы, опять-таки будет сгенерировано непроверяемое исключение RuntimeException.

Методы setLoopi ng и setVolume могут быть использованы при любом состоянии Medi aPl ауег. Они просто служат делегатами соответствующих методов Medi aPlауег.

Метод stop останавливает MediaPlayer и снова устанавливает флаг isPrepared в синхронизированном блоке.

И последний метод в реализации Androi dMusi с – OnCompl eti onLi stener. onCompl et ion. Он просто устанавливает флаг isPrepared в синхронизированном блоке, чтобы другие методы не выдавали ненужные исключения.

Теперь перейдем к классам, обслуживающим ввод информации.

Источник: Mario Zechner / Марио Цехнер, «Программирование игр под Android», пер. Егор Сидорович, Евгений Зазноба, Издательство «Питер»

По теме:

  • Комментарии