Мультимедийный фреймворк Android поддерживает запись и воспроизведение аудио. В этой статье я покажу, как разработать простое приложение для звукозаписи, которое будет записывать аудио и сохранять его в локальном хранилище Android-устройства с помощью MediaRecorder
из Android SDK.
Вы также узнаете, как запросить разрешения у пользователя в режиме реального времени и как работать с локальным хранилищем Android-устройства.
Создание пользовательского интерфейса
Сперва нам нужно создать интерфейс для звукозаписи. Это простой layout с тремя кнопками, которые будут использоваться для запуска, приостановки/возобновления и остановки записи.
<?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:layout_width="match_parent" android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textview_sound_recorder_heading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Sound Recorder"
android:layout_centerHorizontal="true"
android:textSize="32dp"
android:textStyle="bold"
android:textColor="#000"
android:layout_marginTop="32dp"/>
<Button
android:id="@+id/button_start_recording"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start"
android:layout_alignParentBottom="true"
android:layout_marginLeft="32dp"
android:layout_marginBottom="32dp"
android:layout_centerVertical="true"/>
<Button
android:id="@+id/button_pause_recording"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pause"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="32dp"/>
<Button
android:id="@+id/button_stop_recording"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Stop"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginBottom="32dp"
android:layout_marginRight="32dp"/>
</RelativeLayout>
Запрос требуемых разрешений
После создания пользовательского интерфейса мы можем начать использовать MediaRecorder
для реализации основной функциональности нашего приложения. Но сначала нам нужно запросить необходимые разрешения для записи аудио и доступа к локальному хранилищу. Cделаем мы это это с помощью нескольких простых строк кода в нашем файле AndroidManifest.xml
:
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Также нужно проверить, одобрил ли пользователь разрешения, прежде чем мы сможем использовать наш MediaRecorder
. Сделаем это в Activity MainActivity.kt
:
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
val permissions = arrayOf(android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.READ_EXTERNAL_STORAGE)
ActivityCompat.requestPermissions(this, permissions,0)
}
Примечание: позже эти строки кода будут перемещены в OnClickListener
кнопки начала записи аудио, чтобы мы могли убедиться, что MediaRecorder
не будет запущен без необходимых разрешений.
Запись и сохранение аудио
Добавление OnClickListeners
Добавим слушатели к кнопкам, чтобы они реагировали на пользовательские события. Как я упоминал ранее, проверка на наличие необходимых разрешений будет добавлена в OnClickListener кнопки начала записи аудио:
button_start_recording.setOnClickListener {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
val permissions = arrayOf(android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.READ_EXTERNAL_STORAGE)
ActivityCompat.requestPermissions(this, permissions,0)
} else {
startRecording()
}
}
button_stop_recording.setOnClickListener{
stopRecording()
}
button_pause_recording.setOnClickListener {
pauseRecording()
}
Настройка MediaRecorder
Далее нам нужно указать путь для сохранения аудио и настроить MediaRecorder.
private var output: String? = null
private var mediaRecorder: MediaRecorder? = null
private var state: Boolean = false
private var recordingStopped: Boolean = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
output = Environment.getExternalStorageDirectory().absolutePath + "/recording.mp3"
mediaRecorder = MediaRecorder()
mediaRecorder?.setAudioSource(MediaRecorder.AudioSource.MIC)
mediaRecorder?.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
mediaRecorder?.setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
mediaRecorder?.setOutputFile(output)
}
Мы берём путь к корню нашего внешнего хранилища и добавляем в него имя нашей записи и тип файла. После этого мы создаём объект MediaRecorder
и определяем источник звука, аудиокодер, формат и файл для записи.
Запись и сохранение аудио
Код, используемый для запуска MediaRecorder
, определяется в OnClickListener
кнопки начала записи аудио:
private fun startRecording() {
try {
mediaRecorder?.prepare()
mediaRecorder?.start()
state = true
Toast.makeText(this, "Recording started!", Toast.LENGTH_SHORT).show()
} catch (e: IllegalStateException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
}
}
Как видите, нужно вызвать функцию prepare
, прежде чем мы сможем начать запись. Мы также встраиваем вызов в блок try-catch, чтобы приложение не сломалось при сбое функции prepare
.
OnClickListeners
кнопки остановки записи очень похож на код выше.
private fun stopRecording() {
if (state) {
mediaRecorder?.stop()
mediaRecorder?.release()
state = false
} else {
Toast.makeText(this, "You are not recording right now!", Toast.LENGTH_SHORT).show()
}
}
Здесь мы проверяем, работает ли в данный момент MediaRecorder
, прежде чем мы остановим запись, потому что наше приложение сломается, если метод stop
будет вызван, в то время как MediaRecorder
не будет запущен. После этого мы меняем переменную состояния на false
, чтобы пользователь не мог снова нажать кнопку остановки.
Нам осталось определить OnClickListener
для кнопки приостановки/возобновления.
@SuppressLint("RestrictedApi", "SetTextI18n")
@TargetApi(Build.VERSION_CODES.N)
private fun pauseRecording() {
if (state) {
if (!recordingStopped) {
Toast.makeText(this,"Stopped!", Toast.LENGTH_SHORT).show()
mediaRecorder?.pause()
recordingStopped = true
button_pause_recording.text = "Resume"
} else {
resumeRecording()
}
}
}
@SuppressLint("RestrictedApi", "SetTextI18n")
@TargetApi(Build.VERSION_CODES.N)
private fun resumeRecording() {
Toast.makeText(this,"Resume!", Toast.LENGTH_SHORT).show()
mediaRecorder?.resume()
button_pause_recording.text = "Pause"
recordingStopped = false
}
В этих двух методах мы проверяем, работает ли MediaRecorder
. Если работает, мы приостановим запись и изменим текст кнопки для возобновления. При повторном нажатии запись возобновится.
Наконец, мы можем записать аудио и прослушать его, открыв файл recording.mp3
, который будет сохранён в нашем локальном хранилище. Просто откройте проводник файлов и сделайте поиск по имени файла recording.mp3
.
Исходный код
Вот полный исходный код нашего приложения:
package com.example.android.soundrecorder
import android.Manifest
import android.annotation.SuppressLint
import android.annotation.TargetApi
import android.content.pm.PackageManager
import android.media.MediaRecorder
import android.os.Build
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Environment
import android.support.v4.app.ActivityCompat
import android.support.v4.content.ContextCompat
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_main.*
import java.io.IOException
class MainActivity : AppCompatActivity() {
private var output: String? = null
private var mediaRecorder: MediaRecorder? = null
private var state: Boolean = false
private var recordingStopped: Boolean = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mediaRecorder = MediaRecorder()
output = Environment.getExternalStorageDirectory().absolutePath + "/recording.mp3"
mediaRecorder?.setAudioSource(MediaRecorder.AudioSource.MIC)
mediaRecorder?.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
mediaRecorder?.setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
mediaRecorder?.setOutputFile(output)
button_start_recording.setOnClickListener {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
val permissions = arrayOf(android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.READ_EXTERNAL_STORAGE)
ActivityCompat.requestPermissions(this, permissions,0)
} else {
startRecording()
}
}
button_stop_recording.setOnClickListener{
stopRecording()
}
button_pause_recording.setOnClickListener {
pauseRecording()
}
}
private fun startRecording() {
try {
mediaRecorder?.prepare()
mediaRecorder?.start()
state = true
Toast.makeText(this, "Recording started!", Toast.LENGTH_SHORT).show()
} catch (e: IllegalStateException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
}
}
@SuppressLint("RestrictedApi", "SetTextI18n")
@TargetApi(Build.VERSION_CODES.N)
private fun pauseRecording() {
if (state) {
if (!recordingStopped) {
Toast.makeText(this,"Stopped!", Toast.LENGTH_SHORT).show()
mediaRecorder?.pause()
recordingStopped = true
button_pause_recording.text = "Resume"
} else {
resumeRecording()
}
}
}
@SuppressLint("RestrictedApi", "SetTextI18n")
@TargetApi(Build.VERSION_CODES.N)
private fun resumeRecording() {
Toast.makeText(this,"Resume!", Toast.LENGTH_SHORT).show()
mediaRecorder?.resume()
button_pause_recording.text = "Pause"
recordingStopped = false
}
private fun stopRecording(){
if (state) {
mediaRecorder?.stop()
mediaRecorder?.release()
state = false
} else {
Toast.makeText(this, "You are not recording right now!", Toast.LENGTH_SHORT).show()
}
}
}
Заключение
Теперь вы знаете, как работает MediaRecorder
, как запрашивать разрешения в режиме реального времени и почему это важно делать. Вы также узнали о локальном хранилище вашего устройства Android и о том, как хранить в нём данные.
Более сложная версия этого приложения, в которой есть некоторые дополнительные функции, такие как воспроизведение ваших записей с помощью MediaPlayer
, доступна на Github.
Перевод статьи «Create an Android Sound Recorder using Kotlin»
ПОХОЖИЕ ПУБЛИКАЦИИ
- None Found
6 комментариев к статье "Создание собственного Android-диктофона с помощью Kotlin"