Урок 3. Проигрывание музыки

Урок 3. Проигрывание музыки

Сообщение EgorovAD MEPhI » 06 дек 2013, 08:45

В этом уроке будут рассмотрены следующие темы:
• Запуск нового activity;
• Передача дополнительной информации в activity при запуске;
• Получение информации об аудиофайле по id;
• Проигрывание музыки;
• Обработка нажатия на кнопку.
EgorovAD MEPhI
Администратор
 
Сообщений: 155
Зарегистрирован: 04 ноя 2011, 11:49

Запуск нового activity

Сообщение EgorovAD MEPhI » 06 дек 2013, 08:46

Запуск нового activity
Пришло время разобраться, как в простейшем случае реализовать запуск другой activity.
При выборе песни из списка должна вызываться activity проигрывания музыки. Для обработки выбора песни из списка необходимо переопределить метод ListActivity, который называется onListItemClick(...).Сделайте это по аналогии со вторым уроком.
Для открытия нового activity используется метод startActivity(Intent intent). В качестве параметра выступает класс Intent, в котором хранится информация о действии, которое нужно произвести. В данном случае будет храниться информация о том, какое activity нужно запустить. Такой Intent может быть создан следующим образом:
Код: выделить все
Intent startIntent = new Intent (this, PlayActivity.class);

Здесь первый параметр – контекст, а второй – класс activity, которую нужно открыть.
Запустить activity можно при помощи следующего кода:
Код: выделить все
startActivity(startIntent);

Удалите всё автосгенерированное содержимое onListItemClick(...) и добавьте 2 строчки, приведенные выше. Теперь запустите приложение и проверьте, что при нажатии на песню открывается окно проигрывания.
EgorovAD MEPhI
Администратор
 
Сообщений: 155
Зарегистрирован: 04 ноя 2011, 11:49

Передача информации в activity

Сообщение EgorovAD MEPhI » 06 дек 2013, 08:46

Передача информации в activity
Кроме того, что нужно запустить activity, нужно еще и передать туда информацию о песне, которая будет проигрываться. Будет достаточно передать id песни. Данные можно передавать в том же Intent'е, который используется для запуска. В Intent'ах удобно передавать только простые типы, для сложных классов нужны дополнительные действия, но в данном случае всё просто – нужно передать long, хранящий id. Данные в Intent'е передаются, как правило, в виде т.н. extra, для того чтобы записать id, будет достаточно вызвать:
Код: выделить все
startIntent.putExtra("id", id);

В данном случае “id” - это название поля, а id – значение, переданное 4-ым параметром в onListItemClick(...).
EgorovAD MEPhI
Администратор
 
Сообщений: 155
Зарегистрирован: 04 ноя 2011, 11:49

Заполнение информации о песне в PlayActivity

Сообщение EgorovAD MEPhI » 06 дек 2013, 08:48

Заполнение информации о песне в PlayActivity
Сначала в PlayActivity нужно считать id песни из Intent'а. Для этого в OnCreate(…) добавьте:
Код: выделить все
      Intent intent = getIntent();
      long id = intent.getLongExtra("id", -1);

Вторым параметром в getLongExtra(...) передается значение по умолчанию, оно будет присвоено, если extra с таким “ключом” не найдена или её тип не совпадает. Поэтому нужно проверить _id на равенство с -1. В том случае, если id было передано, надо загрузить информацию о песне и заполнить layout. Первым шагом может стать создание URI и курсора. Т.к. Uri понадобится при проигрывании музыки, то есть в других методах, имеет смысл объявить его как поле класса, а не как локальную переменную:
Код: выделить все
private Uri uri;

Создание Uri и курсора делается аналогично уроку 1.
Код: выделить все
if (id != -1) {
         uri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id);
         ContentResolver contentResolver = getContentResolver();
         Cursor cursor = contentResolver.query(uri, null, null, null, null);
         cursor.moveToFirst();

В последней строке приведенного кода происходит переход к первому элементу (элемент будет всего один).
Теперь из полученного курсора можно считать данные и заполнить текстовые поля layout'а. Здесь будет приведен пример, как это сделать для альбома. Остальное (имя исполнителя и название) нужно заполнить самостоятельно.
Код: выделить все
TextView albumView = (TextView) findViewById(R.id.album);
         int albumColumn = cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM);
         String album = cursor.getString(albumColumn);
         albumView.setText(album);

Тут в первой строке получается текстовое поле для альбома, объявленное в layout’е, во 2 и 3 строках происходит чтение названия альбома из курсора, а в 4 строке записывается полученное название.
После выполнения всех операций курсор необходимо закрыть:
Код: выделить все
   cursor.close();
EgorovAD MEPhI
Администратор
 
Сообщений: 155
Зарегистрирован: 04 ноя 2011, 11:49

Проигрывание музыки

Сообщение EgorovAD MEPhI » 06 дек 2013, 08:49

Проигрывание музыки
Для проигрывания медиафайлов в Android используется класс MediaPlayer. Он берет на себя большинство проблем работы с аудио. Итак, для работы аудиоплеера понадобится экземпляр класс MediaPlayer. Лучше всего объявить его как приватное поле.
private MediaPlayer mediaPlayer;
Конструктор лучше всего добавить в onCreate(...):
Код: выделить все
      mediaPlayer = new MediaPlayer();

Для плеера в простейшем случае нужны проигрывание, пауза и остановка проигрывания. Кроме того, необходимо подготовить объект mediaPlayer к использованию. Такую подготовку стоит вынести в отдельный метод.
Код: выделить все
   private boolean prepare() {
      mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
      try {
         mediaPlayer.setDataSource(getApplicationContext(), uri);
         mediaPlayer.prepare();
      } catch (Exception e) {
         return false;
      }
      return true;
   }

В этом методе указываются некоторые параметры для проигрывания аудио и происходит подготовка к проигрыванию. Некоторые методы внесены в секцию try, т.к. объект mediaPlayer не всегда может находиться в нужном состоянии, в этом случае метод вернет значение false.
Также рекомендуется создать переменную, которая бы отражала состояние плеера. Лучше всего для этой цели создать отдельный тип.
private enum State { NOT_VALID, PLAYING, STOPPED, PAUSED };
private State state = State.NOT_VALID;
Теперь можно добавить изменение переменной состояния в метод prepare().
Код: выделить все
   private boolean prepare() {
      mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
      state = State.NOT_VALID;
      try {
         mediaPlayer.setDataSource(getApplicationContext(), uri);
         mediaPlayer.prepare();
         state = State.STOPPED;
      } catch (Exception e) {
         return false;
      }
      return true;
   }

Теперь аналогично prepare() нужно создать методы play(), stop() и pause().
Код: выделить все
   private boolean play() {
      try {
         mediaPlayer.start();
         state = State.PLAYING;
      } catch (IllegalStateException e) {
         state = State.NOT_VALID;
         return false;
      }
      return true;
   }

   private boolean stop() {
      try {
         mediaPlayer.stop();
         state = State.STOPPED;
      } catch (IllegalStateException e) {
         state = State.NOT_VALID;
         return false;
      }
      return true;
   }

   private boolean pause() {
      try {
         mediaPlayer.pause();
         state = State.PAUSED;
      } catch (IllegalStateException e) {
         state = State.NOT_VALID;
         return false;
      }
      return true;
   }

Для того чтобы освободить ресурсы, когда проигрывание музыки больше не нужно, необходимо вызвать release(). Так как для каждого подобного действия был написан отдельный метод, то лучше поддержать единый стиль, несмотря на то что метод будет состоять из одной строки.
Код: выделить все
   private void release() {
      mediaPlayer.release();
   }

Теперь можно поместить вызовы написанных методов в этапы жизненного цикла activity. Первый метод, который вызывается при старте activity – onCreate(...), после него вызывается onStart(). Для каждого из этих методов есть “зеркальные”, которые вызываются при закрытии activity. А именно, сначала вызывается onStop(), а потом onDestroy(). onStop() будет вызван в том случае, если activity уйдет из области видимости и пользователь переключится на другую задачу (при появлении всплывающих диалогов и прочего, перекрывающего activity лишь частично, onStop не вызывается!). Если потом пользователь вернется к activity, для которой был вызван OnStop(), то будет вызван onStart() и activity продолжит работу.
Так как в текущем виде аудиоплеер еще достаточно “сырой”, то имеет смысл выключать проигрывание, когда вызывается onStop(). К примеру, при звонке пользователю совершенно не захочется открывать ваше приложение, чтобы выключить мешающую музыку. Поэтому включение музыки можно сделать в onStart(), а выключение в onStop().
Код: выделить все
   @Override
   protected void onStart() {
      if (prepare())
         play();
      super.onStart();
   }

   @Override
   protected void onStop() {
      stop();
      release();
      super.onStop();
   }

Также необходимо изменить состояние плеера, когда песня закончит проигрываться. Для этого нужно создать обработчик события OnCompletionListener:
Код: выделить все
   private OnCompletionListener completionListener = new OnCompletionListener() {

      @Override
      public void onCompletion(MediaPlayer listener) {
         state = State.STOPPED;
      }
   };

Теперь нужно “связать” обработчик и объект mediaPlayer, лучше всего это сделать сразу после создания объекта плеера.
Код: выделить все
mediaPlayer.setOnCompletionListener(completionListener);
EgorovAD MEPhI
Администратор
 
Сообщений: 155
Зарегистрирован: 04 ноя 2011, 11:49

Обработка нажатия на кнопку проигрывания

Сообщение EgorovAD MEPhI » 06 дек 2013, 08:51

Обработка нажатия на кнопку проигрывания
На layout'е осталась кнопка проигрывания/паузы, поведение которой нигде не описано. Для обработки нажатий используется класс OnClickListener. Обработчик нажатия на кнопку может выглядеть следующим образом:
Код: выделить все
   private OnClickListener playButtonListener = new OnClickListener() {

      @Override
      public void onClick(View v) {
         if (state == State.PLAYING)
            pause();
         else if (state == State.STOPPED || state == State.PAUSED)
            play();
      }
   };

В приведенном коде в зависимости от текущего состояния плеера проигрывание или ставится на паузу или наоборот начинается. Теперь нужно указать, что этот обработчик соответствует кнопке playButton, для этого можно выполнить следующий код:
Код: выделить все
      playButton = (ImageButton) findViewById(R.id.playButton);
      playButton.setOnClickListener(playButtonListener);

Этот код необходимо поместить в onCreate(...) activity.
Кроме изменения состояния плеера, нужно менять еще и картинку на кнопке. Для того чтобы установить картинку со значком паузы, нужно выполнить следующий код:
Код: выделить все
playButton.setImageResource(android.R.drawable.ic_media_pause);

Для того чтобы установить значок проигрывания:
Код: выделить все
playButton.setImageResource(android.R.drawable.ic_media_play);

Расставьте эти вызовы самостоятельно в нужных местах.
Проигрывание должно выглядеть так, как на скриншоте(рисунок 1):
Изображение
Рисунок 1. Проигрывание.
EgorovAD MEPhI
Администратор
 
Сообщений: 155
Зарегистрирован: 04 ноя 2011, 11:49

Результаты и дальнейшая работа

Сообщение EgorovAD MEPhI » 06 дек 2013, 08:52

Результаты и дальнейшая работа
В результате должен был получиться минималистичный Android аудиоплеер. В ходе работы Вы познакомились с некоторыми основными концепциями Android и научились базовым принципам работы с activity.
Для того чтобы полученное приложение стало полноценным плеером, оно должно быть улучшено. В плеер самостоятельно можно добавить следующие возможности:
• Добавить уведомление при проигрывании и проигрывание без открытого activity;
• Добавить окно информации о песне;
• Добавить навигацию между песнями в режиме проигрывания;
• Добавить разные режимы работы: проигрывание по исполнителю, альбому и т.д.;
• Режим shuffle;
• И другое.
EgorovAD MEPhI
Администратор
 
Сообщений: 155
Зарегистрирован: 04 ноя 2011, 11:49


Вернуться в Задания и примеры

Кто сейчас на форуме

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2