创新实训——第五周2

    这次的工作在上次的基础上完成录音发送功能。

    自定义AudioRecordButton类继承自Button,用于实现聊天时的录音和发送语音及其他一些相关功能。

    构造方法,设置按钮样式以及提示用户可以按住按钮说话

public AudioRecordButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // 初始化按钮样式
        setBackgroundResource(R.drawable.record_button_normal);
        setText(getResources().getString(R.string.press_record));//按住 说话
    }

     初始化按钮,并设置长按按钮的事件监听器。

public void init(String audioSaveDir) {
        mAudioSaveDir = audioSaveDir;
        // 初始化 dialog 管理器
        mDialogManager = new RecordDialogManager(getContext());
        // 获取音频管理,以申请音频焦点
        mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
        // 初始化录音管理器
        mAudioRecordManager = AudioRecordManager.getInstance(mAudioSaveDir);

        mAudioRecordManager.setAudioStateListener(this);

        // 设置按钮长按事件监听,只有触发长按才开始准备录音
        setOnLongClickListener(new OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                // 获取焦点
                int focus = mAudioManager.requestAudioFocus(null,
                        AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
                if (focus == AudioManager.AUDIOFOCUS_REQUEST_GRANTED){
                    isReady = true;
                    mAudioRecordManager.prepareAudio();
                }else if (focus == AudioManager.AUDIOFOCUS_REQUEST_FAILED){
                    if (mRecordingListener != null) {
                        mRecordingListener.recordError("AUDIO_FOCUS_REQUEST_FAILED");
                    }
                }
                return true;
            }
        });
        hasInit = true;
    }

    子线程runnable,每间隔0.1秒获取音量大小,并记录录音时间

    private Runnable mGetVoiceLevelRunnable = new Runnable() {
        @Override
        public void run() {
            while (isRecording) {
                try {
                    Thread.sleep(100);
                    mRecordTime += 100;
                    mHandler.sendEmptyMessage(MSG_VOICE_CHANGE);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };

    通过Handler关联子线程,通过Handler将Message和Runnable对象发送到该Handler所关联线程的MessageQueue(消息队列)中,然后该消息队列一直在循环拿出一个Message,对其进行处理,处理完之后拿出下一个Message,继续进行处理,周而复始。

@SuppressLint("HandlerLeak")
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case MSG_AUDIO_PREPARED:
                    // 录音管理器 prepare 成功,开始录音并显示dialog
                    // 启动线程记录时间并获取音量变化
                    isRecording = true;
                    mDialogManager.showDialogRecord();
                    // 启动线程,每隔0.1秒获取音量大小
                    new Thread(mGetVoiceLevelRunnable).start();
                    break;
                case MSG_VOICE_CHANGE:
                    mDialogManager.updateVoiceLevel(mAudioRecordManager.getVoiceLevel(7));
                    break;
                case MSG_DIALOG_DISMISS:
                    mDialogManager.dismissDialog();
                    break;
            }
        }
    };

录音准备完成和录音结束时的回调函数

     // 录音准备出错时回调
    @Override
    public void prepareError(String message) {
        if (mRecordingListener != null) {
            mRecordingListener.recordError(message);
        }
    }

    // 录音准备完成后回调
    @Override
    public void prepareFinish(String audioFilePath) {
        mAudioFilePath = audioFilePath;
        mHandler.sendEmptyMessage(MSG_AUDIO_PREPARED);
    }

根据用户动作(移动、松开、长按)判断对应的操作(取消、发送等)

@Override
    public boolean onTouchEvent(MotionEvent event) {
        if (!hasInit) {
            return true;
        }
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                changeState(STATE_RECORDING);
                break;
            case MotionEvent.ACTION_MOVE:
                if (isRecording) {
                    if (isWantToCancel(x, y)) {
                        changeState(STATE_WANT_CANCEL);
                    } else {
                        changeState(STATE_RECORDING);
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
                // 未触发 longClick,直接重置
                if (!isReady) {
                    reset();
                    return super.onTouchEvent(event);
                }
                // 触发了longClick,开始初始化录音,但是为初始化完成,或者录音时间太短
                if (!isRecording || mRecordTime < 0.8f) {
                    mDialogManager.showDialogToShort();
                    mAudioRecordManager.cancelAudio();
                    mHandler.sendEmptyMessageDelayed(MSG_DIALOG_DISMISS, 1000);
                } else if (mCurrentState == STATE_RECORDING) {
                    mDialogManager.dismissDialog();
                    mAudioRecordManager.releaseAudio();
                    // 将录音文件路径和录音时长回调
                    if (mRecordingListener != null) {
                        mRecordingListener.recordFinish(mAudioFilePath, mRecordTime);
                    }
                } else if (mCurrentState == STATE_WANT_CANCEL) {
                    mDialogManager.dismissDialog();
                    mAudioRecordManager.cancelAudio();
                }
                reset();
                break;
        }
        return super.onTouchEvent(event);
    }

改变录音提示状态,包括“按住 说话”、“松开 发送”、“松开手指 取消发送”

private void changeState(int state) {
        if (mCurrentState != state) {
            mCurrentState = state;
            if (state == STATE_NORMAL) {
                setText(getResources().getString(R.string.press_record));
                setBackgroundResource(R.drawable.record_button_normal);
            } else if (state == STATE_RECORDING) {
                setText(getResources().getString(R.string.release_end));
                setBackgroundResource(R.drawable.record_button_recoding);
                if (isRecording) {
                    mDialogManager.showRecording();
                }
            } else if (state == STATE_WANT_CANCEL) {
                setText(getResources().getString(R.string.release_cancel));
                setBackgroundResource(R.drawable.record_button_recoding);
                if (isRecording) {
                    mDialogManager.showDialogWantCancel();
                }
            }
        }
    }

    判断是否要取消语音发送,通过判断触控点的x、y坐标变化来判断用户行为。

private boolean isWantToCancel(int x, int y) {
        return x < 0 || x > getWidth()
                || y < -CANCEL_HEIGHT || y > getHeight() + CANCEL_HEIGHT;
    }

    释放资源,释放音频焦点

private void reset() {
        isReady = false;
        isRecording = false;
        mRecordTime = 0;
        changeState(STATE_NORMAL);

        // 释放焦点
        if (mAudioManager != null){
            mAudioManager.abandonAudioFocus(null);
        }
    }

    然后在上周的文本输入框中添加发送录音的功能

// 录音按钮初始化和录音监听
        mBtnAudioRecord.init(Constant.APP_CACHE_AUDIO);
        mBtnAudioRecord.setRecordingListener(new AudioRecordButton.OnRecordingListener() {
            @Override
            public void recordFinish(String audioFilePath, long recordTime) {
                if (mLayoutListener != null) {
                    mLayoutListener.audioRecordFinish(audioFilePath, recordTime);
                }
            }

            @Override
            public void recordError(String message) {
                if (mLayoutListener != null) {
                    mLayoutListener.audioRecordError(message);
                }
            }
        });

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值