В этом руководстве мы создадим базовое приложение для записи звука. Оно работает аналогично встроенному приложению Android recorder, но имеет очень простой пользовательский интерфейс.
ПРИМЕЧАНИЕ: Этот туториал предназначен для новичков и начинающих разработчиков Android. Я предполагаю, что вы уже знакомы с некоторыми основами программирования Android.
Вы узнаете о классе MediaRecorder, как получить разрешения пользователя (в Android M и выше) и как получить доступ к внешнему хранилищу на android.
Давайте начнем разработку!
Самый распространенный способ записи медиа — это класс MediaRecorder. В нашем файле MainActivity.java мы создадим myAudioRecorder из класса MedianRecorder. Мы предоставим ему источник звука (микрофон) и зададим формат вывода 3Gpp. Для хранения записи будем использовать место на внешнем хранилище.
private MediaRecorder myAudioRecorder; output = Environment.getExternalStorageDirectory().getAbsolutePath() + "/myrecording.3gp"; myAudioRecorder = new MediaRecorder(); myAudioRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); myAudioRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); myAudioRecorder.setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB); myAudioRecorder.setOutputFile(output);
Примечание: С каждой новой записью предыдущая будет удаляться, так как каждая запись записывается в один и тот же файл.
В случае если вы хотите сохранить все файлы, вы можете сохранить их в отдельных файлах. (Воспринимайте это как личное задание!)
Используются три кнопки:
1) START
2) STOP
3) PLAY
start = (Button)findViewById(R.id.button1); stop = (Button) findViewById(R.id.button2); play = (Button)findViewById(R.id.button3); start.setOnClickListener(this); stop.setOnClickListener(this); play.setOnClickListener(this);
Функция прослушивания:
@Override public void onClick(View v){ switch (v.getId()){ case R.id.button1: start(v); break; case R.id.button2: stop(v); break; case R.id.button3: try { play(v); } catch (IOException e){ Log.i("IOException", "Error in play"); } break; default: break; } }
Интуитивно понятно, что кнопки работают так, как они названы. Теперь мы присоединим объект myAudioRecorder к событиям onClickListener отдельных кнопок, чтобы начать и сохранить запись. Для кнопок START и STOP:
public void start(View view){ try{ myAudioRecorder.prepare(); myAudioRecorder.start(); } catch (IllegalStateException e){ e.printStackTrace(); } catch (IOException e){ e.printStackTrace(); } start.setEnabled(false); stop.setEnabled(true); Toast.makeText(getApplicationContext(), "Recording started", Toast.LENGTH_SHORT).show(); } public void stop(View view){ myAudioRecorder.stop(); myAudioRecorder.release(); myAudioRecorder = null; stop.setEnabled(false); play.setEnabled(true); Toast.makeText(getApplicationContext(), "Audio recorded successfully", Toast.LENGTH_SHORT).show(); }
Toast показывает «Запись началась», когда начинается запись. Аналогично мы видим toast, когда запись сохраняется. Для PLAY мы прочитаем выходной файл и воспроизведем его через объект MediaPlayer. Снова отображается toast для воспроизведения аудио. Нам нужно добавить блоки try-catch в различных местах, чтобы избежать сбоев.
public void play(View view) throws IllegalArgumentException, SecurityException, IllegalStateException, IOException { MediaPlayer m = new MediaPlayer(); m.setDataSource(output); m.prepare(); m.start(); Toast.makeText(getApplicationContext(), "Playing audio", Toast.LENGTH_SHORT).show(); }
В UI (пользовательском интерфейсе) мы просто добавим три кнопки, как указано выше. Файл activity_main.xml выглядит следующим образом:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.example.india.recorder.MainActivity"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_marginTop="50dp" android:text="Start" android:id="@+id/button1"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_marginTop="175dp" android:text="Stop" android:id="@+id/button2"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_marginTop="300dp" android:text="Play" android:id="@+id/button3"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Welcome to Recorder!" android:layout_centerHorizontal="true" android:fontFamily="sans-serif" android:layout_marginTop="400dp" android:textSize="25dp" android:textColor="#008080"/> </RelativeLayout>
Нам понадобятся разрешения пользователей для доступа к MIC и хранилищу, поэтому мы добавим разрешения в Android_Manifest.xml
ПРИМЕЧАНИЕ: Разрешения изменились в Android M. Теперь разрешения запрашиваются во время выполнения, а не во время установки, как это было в Android M.
Чтобы решить эту проблему, мы добавим проверку в наш код, чтобы определить версию Android mobile, с которой мы работаем, и действовать соответствующим образом.
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode){ case 200: permissionToRecordAccepted = grantResults[0] == PackageManager.PERMISSION_GRANTED; permissionToWriteAccepted = grantResults[1] == PackageManager.PERMISSION_GRANTED; break; } if (!permissionToRecordAccepted ) MainActivity.super.finish(); if (!permissionToWriteAccepted ) MainActivity.super.finish(); }
Добавьте необходимые разрешения в Android.manifest для record_audio и file_storage.
<uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Теперь соберите проект и запустите приложение. Оно должно запросить разрешения, когда вы откроете его в первый раз.
Все должно работать, как ожидалось.
Полный файл MainActivity.java выглядит следующим образом:
package com.example.india.recorder; import android.Manifest; import android.content.pm.PackageManager; import android.media.MediaPlayer; import android.media.MediaRecorder; import android.os.Build; import android.os.Environment; import android.support.annotation.NonNull; import android.support.v4.app.ActivityCompat; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.View; import android.widget.Button; import android.widget.Toast; import java.io.IOException; public class MainActivity extends AppCompatActivity implements View.OnClickListener { public static final int RECORD_AUDIO = 0; private MediaRecorder myAudioRecorder; private String output = null; private Button start, stop, play; private boolean permissionToRecordAccepted = false; private boolean permissionToWriteAccepted = false; private String [] permissions = {"android.permission.RECORD_AUDIO", "android.permission.WRITE_EXTERNAL_STORAGE"}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); int requestCode = 200; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { requestPermissions(permissions, requestCode); } start = (Button)findViewById(R.id.button1); stop = (Button) findViewById(R.id.button2); play = (Button)findViewById(R.id.button3); start.setOnClickListener(this); stop.setOnClickListener(this); play.setOnClickListener(this); stop.setEnabled(false); play.setEnabled(false); output = Environment.getExternalStorageDirectory().getAbsolutePath() + "/myrecording.3gp"; myAudioRecorder = new MediaRecorder(); myAudioRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); myAudioRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); myAudioRecorder.setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB); myAudioRecorder.setOutputFile(output); } @Override public void onClick(View v){ switch (v.getId()){ case R.id.button1: start(v); break; case R.id.button2: stop(v); break; case R.id.button3: try { play(v); } catch (IOException e){ Log.i("IOException", "Error in play"); } break; default: break; } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode){ case 200: permissionToRecordAccepted = grantResults[0] == PackageManager.PERMISSION_GRANTED; permissionToWriteAccepted = grantResults[1] == PackageManager.PERMISSION_GRANTED; break; } if (!permissionToRecordAccepted ) MainActivity.super.finish(); if (!permissionToWriteAccepted ) MainActivity.super.finish(); } public void start(View view){ try{ myAudioRecorder.prepare(); myAudioRecorder.start(); } catch (IllegalStateException e){ e.printStackTrace(); } catch (IOException e){ e.printStackTrace(); } start.setEnabled(false); stop.setEnabled(true); Toast.makeText(getApplicationContext(), "Recording started", Toast.LENGTH_SHORT).show(); } public void stop(View view){ myAudioRecorder.stop(); myAudioRecorder.release(); myAudioRecorder = null; stop.setEnabled(false); play.setEnabled(true); Toast.makeText(getApplicationContext(), "Audio recorded successfully", Toast.LENGTH_SHORT).show(); } public void play(View view) throws IllegalArgumentException, SecurityException, IllegalStateException, IOException { MediaPlayer m = new MediaPlayer(); m.setDataSource(output); m.prepare(); m.start(); Toast.makeText(getApplicationContext(), "Playing audio", Toast.LENGTH_SHORT).show(); } }