完美解决录音权限问题并附上录音代码

这段时间做一个项目有即时聊天功能,里面有遇到录音权限的问题,百度了个遍判断权限问题,没有好的解决方案,然而自己代码变通了一下,发现问题其实也还好,先附上录音工具
package .view;

import android.app.Dialog;
import android.content.Context;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

import com.app.application.AppConfig;
import com.app.tool.FToast;
import com.nbappdev.aikaopu_personal.R;
import com.nbappdev.aikaopu_personal.utils.AudioManager;

/**
 * 自定语音按钮
 */
public class AudioRecordButton extends Button implements AudioManager.AudioStageListener{

    private Dialog mDialog;   //语音对话框
    private ImageView mIcon;
    private ImageView mVoice;
    private TextView mLable;
    private Context mContext;

    private AudioManager mAudioManager;
    private boolean mReady=false;  //开始录制
    private boolean isRecording = false;   //是否开始录音
    private boolean recordPermissions = true;   //录音权限
    private float mTime = 0;   //时间

    private static final int MSG_AUDIO_PREPARED = 0X110;
    private static final int MSG_VOICE_CHANGE = 0X111;
    private static final int MSG_DIALOG_DIMISS = 0X112;
    private static final int MSG_VOICE_TIME_OUT = 0X113;
    private AudioRecordButtonHandler mHandler = new AudioRecordButtonHandler();

    private static final int STATE_NORMAL = 1;
    private static final int STATE_RECORDING = 2;
    private static final int STATE_WANT_TO_CANCEL = 3;
    private int mCurrentState = STATE_NORMAL;

    private static final int DISTANCE_Y_CANCEL = 50;

    private boolean time_out = false;   //录制超时
    private Runnable runnable;
    private Handler handler;

    private OnFinishedRecordListener onFinishedRecordListener;


    public void setOnFinishedRecordListener(OnFinishedRecordListener onFinishedRecordListener) {
        this.onFinishedRecordListener = onFinishedRecordListener;
    }

    public AudioRecordButton(Context context) {
        super(context);
        this.mContext = context;
    }

    public AudioRecordButton(final Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;
        if( Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){   //判断SD卡是否存在
            mAudioManager = AudioManager.getInstance(AppConfig.DIR_AUDIO);
            mAudioManager.setOnAudioStageListener(this);
            recordPermissions = true;
        }else {
            FToast.show(mContext,"未发现sd卡,无法使用录音功能");
        }
    }

    private class AudioRecordButtonHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_AUDIO_PREPARED:
                    mTime = 0;
                    showRecordingDialog();
                    isRecording = true;
                    new Thread(mGetVoiceLevelRunnable).start();
                    handler = new Handler();
                    runnable = new Runnable() {
                        @Override
                        public void run() {
                            mHandler.sendEmptyMessage(MSG_VOICE_TIME_OUT);
                        }
                    };
                    handler.postDelayed(runnable, 61000);
                    break;
                case MSG_VOICE_CHANGE:
                    updateVoiceLevel(mAudioManager.getVoiceLevel(7));
                    break;
                case MSG_DIALOG_DIMISS:
                    mAudioManager.cancel();
                    dimissDialog();
                    break;
                case MSG_VOICE_TIME_OUT:
                    time_out = true;
                    dimissDialog();
                    mAudioManager.release();
                    if (onFinishedRecordListener!=null && mReady) {
                        if (mTime>60){
                            mTime = 60;
                        }
                        onFinishedRecordListener.onFinishedRecord(mAudioManager.getCurrentFilePath(),(int)mTime);
                        FToast.show(mContext, "录制时间不能超过60秒");
                    }
                    handler.removeCallbacks(runnable);
                    reset();
                    break;
            }
        }
    };

    /**
     * 监听屏幕触摸事件
     * @param event
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (action) {
            case MotionEvent.ACTION_DOWN:   //按下
                changeDialogState(STATE_RECORDING);
                break;
            case MotionEvent.ACTION_MOVE:   //移动时
                if (isRecording) {
                    if (wantToCancel(x, y)) {
                        changeDialogState(STATE_WANT_TO_CANCEL);
                    }else {
                        changeDialogState(STATE_RECORDING);
                    }
                }
                break;
            case MotionEvent.ACTION_UP:   //抬起时
                if (time_out){
                    time_out = false;
                    return super.onTouchEvent(event);
                }
                if (!mReady) {
                    reset();
                    return super.onTouchEvent(event);
                }
                if (!isRecording || mTime < 0.6f) {
                    tooShort();
                    mAudioManager.cancel();
                    reset();
                    mHandler.sendEmptyMessageDelayed(MSG_DIALOG_DIMISS,0);
                }else if (mCurrentState == STATE_RECORDING) {
                    dimissDialog();
                    mAudioManager.release();
                    if (onFinishedRecordListener!=null) {
                        if (mTime>60){
                            mTime =60;
                        }
                        onFinishedRecordListener.onFinishedRecord(mAudioManager.getCurrentFilePath(),(int)mTime);
                    }
                    reset();
                }else if (mCurrentState == STATE_WANT_TO_CANCEL) {
                    mAudioManager.cancel();
                    dimissDialog();
                    reset();
                }
                break;
        }
        return super.onTouchEvent(event);
    }

    /**
     * 改变对话框状态
     * @param state
     */
    private void changeDialogState(int state) {
        if (mCurrentState != state) {
            mCurrentState = state;
            switch (mCurrentState) {
                case STATE_NORMAL:
                    setBackgroundResource(R.drawable.button_recordnormal);
                    setText("按住 说话");
                    break;
                case STATE_RECORDING:
                    setBackgroundResource(R.drawable.button_recording);
                    setText("松开 结束");
                    if (isRecording) {
                        recording();
                    }
                    break;
                case STATE_WANT_TO_CANCEL:
                    setBackgroundResource(R.drawable.button_recording);
                    setText("松开手指,取消发送");
                    wantToCancel();
                    break;
            }
        }
    }

    private boolean wantToCancel(int x, int y) {
        if (x < 0 || x > getWidth()) {    // 判断是否在左边,右边,上边,下边
            return true;
        }
        if (y < -DISTANCE_Y_CANCEL || y > getHeight() + DISTANCE_Y_CANCEL) {
            return true;
        }
        return false;
    }

    private void reset() {
        isRecording = false;
        changeDialogState(STATE_NORMAL);
        mReady = false;
        mTime = 0;
    }

    /**
     * 开始录音
     */
    public void startRecord(){
        if (recordPermissions){
            mReady = true;
            mAudioManager.prepareAudio();
        }
    }

    @Override
    public boolean onPreDraw() {
        return false;
    }

    //*****************************************Diaolog语音对话框********************************//

    /**
     * 显示语音对话框
     */
    public void showRecordingDialog() {
        mDialog = new Dialog(mContext, R.style.Theme_audioDialog);
        LayoutInflater inflater = LayoutInflater.from(mContext);
        View view = inflater.inflate(R.layout.voice_dialog, null);
        mDialog.setContentView(view);
        mIcon = (ImageView) mDialog.findViewById(R.id.dialog_icon);
        mVoice = (ImageView) mDialog.findViewById(R.id.dialog_voice);
        mLable = (TextView) mDialog.findViewById(R.id.recorder_dialogtext);
        mDialog.show();
    }

    /**
     * 设置正在录音时的dialog界面
     */
    public void recording() {
        if (mDialog != null && mDialog.isShowing()) {
            mIcon.setVisibility(View.VISIBLE);
            mVoice.setVisibility(View.VISIBLE);
            mLable.setVisibility(View.VISIBLE);
            mIcon.setImageResource(R.drawable.recorder);
            mLable.setText("手指上滑,取消发送");
        }
    }

    /**
     * 取消录制
     */
    public void wantToCancel() {
        if (mDialog != null && mDialog.isShowing()) {
            mIcon.setVisibility(View.VISIBLE);
            mVoice.setVisibility(View.GONE);
            mLable.setVisibility(View.VISIBLE);
            mIcon.setImageResource(R.drawable.cancel);
            mLable.setText("松开手指,取消发送");
        }
    }

    /**
     * 录制时间过短
     */
    public void tooShort() {
        if (mDialog != null && mDialog.isShowing()) {
            mIcon.setVisibility(View.VISIBLE);
            mVoice.setVisibility(View.GONE);
            mLable.setVisibility(View.VISIBLE);
            mIcon.setImageResource(R.drawable.voice_to_short);
            mLable.setText("录音时间过短");
        }
    }

    /**
     * 隐藏dialog
     */
    public void dimissDialog() {
        if (mDialog != null && mDialog.isShowing()) {
            mDialog.dismiss();
            mDialog = null;
        }
    }

    public void updateVoiceLevel(int level) {
        if (mDialog != null && mDialog.isShowing()) {
            int resId = mContext.getResources().getIdentifier("v" + level,
                    "drawable", mContext.getPackageName());
            mVoice.setImageResource(resId);
        }
    }

    /**
     * 开始录制
     */
    @Override
    public void wellPrepared() {
        Log.i("触发","准备完成");
        mHandler.sendEmptyMessage(MSG_AUDIO_PREPARED);
    }

    /**
     * 异步获取音量
     */
    private Runnable mGetVoiceLevelRunnable = new Runnable() {
        @Override
        public void run() {
            while (isRecording) {
                try {
                    Thread.sleep(100);
                    mTime += 0.1f;
                    mHandler.sendEmptyMessage(MSG_VOICE_CHANGE);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };

    /**
     * 录制完成回调
     */
    public interface OnFinishedRecordListener {
        void onFinishedRecord(String audioPath,int voice_length);
    }
}

然后录音管理工具类
package .utils;

import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.util.Log;

import java.io.File;
import java.io.IOException;

/**
 * 语音录制管理类
 */
public class AudioManager {

    private MediaRecorder mRecorder;
    private String mDirString;  //文件夹路径
    private String mCurrentFilePathString; //当前的详细路径

    private static AudioManager mInstance;
    public AudioStageListener mListener;
    private boolean isPrepared;

    // 音频获取源
    public static int audioSource = MediaRecorder.AudioSource.MIC;
    // 设置音频采样率,44100是目前的标准,但是某些设备仍然支持22050,16000,11025
    public static int sampleRateInHz = 44100;
    // 设置音频的录制的声道CHANNEL_IN_STEREO为双声道,CHANNEL_CONFIGURATION_MONO为单声道
    public static int channelConfig = AudioFormat.CHANNEL_IN_STEREO;
    // 音频数据格式:PCM 16位每个样本。保证设备支持。PCM 8位每个样本。不一定能得到设备支持。
    public static int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
    // 缓冲区字节大小
    public static int bufferSizeInBytes = 0;

    public void setOnAudioStageListener(AudioStageListener listener) {
        mListener = listener;
    }

    private AudioManager(String dir) {
        mDirString=dir;
    }

    public static AudioManager getInstance(String dir) {
        if (mInstance == null) {
            synchronized (AudioManager.class) {
                if (mInstance == null) {
                    mInstance = new AudioManager(dir);
                }
            }
        }
        return mInstance;
    }

    /**
     * 准备开始录制
     */
    public void prepareAudio() {
        try {
            isPrepared = false;
            File dir = new File(mDirString);
            if (!dir.exists()) {
                dir.mkdirs();
            }
            String fileNameString = System.currentTimeMillis()+".m4a";
            File file = new File(dir, fileNameString);

            mCurrentFilePathString = file.getAbsolutePath();
            mRecorder = new MediaRecorder();
            // 设置输出文件
            mRecorder.setOutputFile(file.getAbsolutePath());
            // 设置meidaRecorder的音频源是麦克风
            mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
            // 设置文件音频的输出格式为MPEG_4
            mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
            // 设置音频的编码格式为AAC
            mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
            mRecorder.prepare();
            mRecorder.start();
            isPrepared = true;
            Log.i("调用","开始调用");
            if (mListener != null) {
                mListener.wellPrepared();
            }
        } catch (IllegalStateException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }



    /**
     * 获取声音的涨幅
     * @param maxLevel
     * @return
     */
    public int getVoiceLevel(int maxLevel) {
        if (isPrepared) {
            try {
                return maxLevel * mRecorder.getMaxAmplitude() / 32768 + 1;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return 1;
    }

    /**
     * 资源释放
     */
    public void release() {
        try {
            if (mRecorder!=null){
                mRecorder.stop();
                mRecorder.release();
                mRecorder = null;
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }


    public void cancel() {
        release();
        if (mCurrentFilePathString != null) {
            File file = new File(mCurrentFilePathString);
            file.delete();
            mCurrentFilePathString = null;
        }
    }

    /**
     *判断是否有录音权限
     * @return
     */
    public static boolean isHasPermission(){
        bufferSizeInBytes = 0;
        bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz,
                channelConfig, audioFormat);
        AudioRecord audioRecord =  new AudioRecord(audioSource, sampleRateInHz,
                channelConfig, audioFormat, bufferSizeInBytes);
        try{
            audioRecord.startRecording();
        }catch (IllegalStateException e){
            e.printStackTrace();
        }
        Log.i("录音权限","录音权限"+audioRecord.getRecordingState());
        if (audioRecord.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING) {
            return false;
        }
        audioRecord.stop();
        audioRecord.release();
        audioRecord = null;
        return true;
    }

    /**
     * 获取当前语音的路径
     * @return
     */
    public String getCurrentFilePath() {
        return mCurrentFilePathString;
    }

    public interface AudioStageListener {
        void wellPrepared();
    }
}

布局文件我就不贴了,开始调用录音之前
if (AudioManager.isHasPermission()){
           down_talk.startRecord();   //开始录音
}
判断一下就行了,第一次弄录音功能,代码都是网上找的,然后自己稍微改一下,这个判断其实你只要静态注册了录音权限的话都会返回true的,这里的作用只是真正录音之前先
让用户允许录音权限而已,然后执行开始录音,因为第一次肯定会弹起录音权限对话框,所以当你手指离开的时候会调用onTouchEvent的MotionEvent.ACTION_UP事件,这地方
我判断了很多因素,基本上只会执行走正确流程的录音方式
 
  
 
  


 
  

 
  

你可能感兴趣的:(安卓开发)