kotlin写的android 录音实例(需要动态申请权限),利用 mediaRecorder 实现

这是一个简单的android 录音单元功能实现的源码,不涉及其他线程或服务之类的深入知识,详细针对 mediaRecorder 实现录音功能做记录和解析。
一 静态权限

现在的Android机已经普遍都是6.0以上的系统了,所以很多权限是需要动态申请的,这里录音权限就需要进行动态申请,我们把需要的权限先在 manifest.xml 文件中静态声明一下

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.RECORD_AUDIO"></uses-permission>

用到的就是上面这三个,包括存储空间的读,写,录音权限
这里只是静态权限的申请,6.0以上的系统还需要动态申请权限,后面的代码会逐步解析。

二 录音文件存放的位置

这里要说明的是,从Android 7.0 之后,系统加强了SD卡的权限管理,即使App声明了完整的SD卡操作权限,系统仍然默认禁止该App访问外部存储。不过系统默认关闭的存储只是外部存储的公共空间,而外部存储的私有空间依然可以正常读写。这个私有空间是只有应用自己才可访问的专享空间,而当这个APP卸载时这个空间也就一起被清理掉了。

在网上很多源码中提到使用 Environment.getExternalStroagePublicDirector 方法获取文件的存放路径,但其实这个方法在比较高版本的SDK中已经废弃了,当使用AS写代码时会有废弃的提示。因为这个方法返回的是公共空间的地址,App自身要操作这个空间很多时候是无法使用的。

那么我们就要获取App的私有空间地址,这里要用到的方法就是 getExternalFilesDir() 。这个方法返回的是一个File类的对象,详细的用法可参考这篇文章app私有空间路径的获取

简单的示例如下

var privatePath = getExternalFilesDir(null).toString()

这个 privatePath 获取的路径位于 “外部存储根目录/Android/data/应用包名/files” 下,注意这里最后是没有 “ / ” 的,也就是说后期要组合一些其他的下级文件路径不要忘了给它后面加“ / ”

三 录音API mediaRecorder 的使用

这个的用法还是挺简单的,下面直接通过源码说明

(1)布局文件源码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/tv_path"/>
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/btn_start"
        android:text="开始"/>
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/btn_stop"
        android:enabled="false"
        android:text="停止"/>


</LinearLayout>

这个 id为 tv_path 的TextView 用于显示存储路径

(2)MainActivity.kt 源码

package com.example.recorder

import android.Manifest
import android.content.pm.PackageManager
import android.media.MediaRecorder
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Environment
import kotlinx.android.synthetic.main.activity_main.*
import org.jetbrains.anko.toast
import java.io.File
import java.io.IOException

class MainActivity : AppCompatActivity() {
    private var sdcardfile : File? = null
    private var recorder : MediaRecorder? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        getSDCardFile()

        btn_start.setOnClickListener {
            if(checkSelfPermission(Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED){
                requestPermissions(arrayOf<String>(Manifest.permission.RECORD_AUDIO),1)
            }else{
                startRecord()
            }
        }

        btn_stop.setOnClickListener{
            stopRecord()
        }
    }
	
	//获取存储路径
    private fun getSDCardFile(){
        if(Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED){
            sdcardfile = getExternalFilesDir(null)
            tv_path.text = sdcardfile.toString()
        }else{
            toast("未找到内存卡")
        }
    }
	
	//开始录音
    private fun startRecord(){
        recorder = MediaRecorder()

		//设置音频源
        recorder!!.setAudioSource(MediaRecorder.AudioSource.MIC)
        //设置输出格式
        recorder!!.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP)
        //设置音频编码
        recorder!!.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB)
        try{
            var file = File.createTempFile("录音_",".amr",sdcardfile)
            //设置录音保存路径
            recorder!!.setOutputFile(file)
            //准备和启动录制音频
            recorder!!.prepare()
            recorder!!.start()
        }catch (e : IOException){
            e.printStackTrace()
        }
        btn_start.isEnabled = false
        btn_stop.isEnabled = true
    }
	
	//停止录音
    private fun stopRecord(){
        try{
            recorder!!.stop()
            recorder!!.release()
            recorder = null
        }catch (e:Exception){
            e.printStackTrace()
        }
        btn_start.isEnabled = true
        btn_stop.isEnabled = false

    }
	
	//动态申请权限的回调函数
    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        if(requestCode == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
            startRecord()
        }else{
            toast("用户拒绝了权限")
        }
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    }

}

以上源码还是很容易理解的,录音的流程如下
(1) 声明 MediaRecorder 的实例 recorder = MediaRecorder()
(2) 设置音频源 recorder!!.setAudioSource(MediaRecorder.AudioSource.MIC)
(3) 设置输出格式 recorder!!.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP)
(4) 设置音频编码 recorder!!.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB)
(5) 设置输出路径 recorder!!.setOutputFile(file)
(6) 准备和启动录制音 recorder!!.prepare() recorder!!.start()

关闭录音的方法也很简单,直接看源码就完全能理解

四 动态权限的申请

这里是一个需要理解的地方,不然很多东西没法做,我们看到 btn_start 监听器下的源码中有一段程序

if(checkSelfPermission(Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED){
    requestPermissions(arrayOf<String>(Manifest.permission.RECORD_AUDIO),1)
 }

这里就是先判断App是否有需要的权限,如果我们需要的权限没有开通,就通过 requestPermissions() 方法申请开通该权限.

程序运行到这里后,用户的界面就会弹出授权提示框.

用户不管是点击了同意授权还是不同意,程序就会执行回调函数onRequestPermissionsResult() .

在该回调函数中,如果用户同意了该授权,就可以继续做录音的程序,如果不同意,我们可以输出一些提示。


以上纯手工码字,如发现错误请不吝赐教,我会及时修改

项目源码在这里
recorder.zip

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值