Android開發--仿微信語音對講錄音

來源:互聯網
上載者:User

Android開發--仿語音對講錄音

自出現以來取得了很好的成績,語音對講的實現更加方便了人與人之間的交流。今天來實踐一下的語音對講的錄音實現,這個也比較容易實現。在此,我將該按鈕封裝成為一個控制項,並通過策略模式的方式實現錄音和介面的解耦合,以方便我們在實際情況中對錄音方法的不同需求(例如想要實現wav格式的編碼時我們也就不能再使用MediaRecorder,而只能使用AudioRecord進行處理)。

實現思路

1.在中我們可以看到實現語音對講的是通過點按按鈕來完成的,因此在這裡我選擇重新自己的控制項使其繼承自Button並重寫onTouchEvent方法,來實現對錄音的判斷。
2.在onTouchEvent方法中,
當我們按下按鈕時,首先顯示錄音的對話方塊,然後調用錄音準備方法並開始錄音,接著開啟一個計時線程,每隔0.1秒的時間擷取一次錄音音量的大小,並通過Handler根據音量大小更新Dialog中的顯示圖片;
當我們移動手指時,若手指向上移動距離大於50,在Dialog中顯示鬆開手指取消錄音的提示,並將isCanceled變數(表示我們最後是否取消了錄音)置為true,上移動距離小於20時,我們恢複Dialog的圖片,並將isCanceled置為false;
當抬起手指時,我們首先關閉錄音對話方塊,接著調用錄音停止方法並關閉計時線程,然後我們判斷是否取消錄音,若是的話則刪除錄音檔案,否則判斷計時時間是否太短,最後調用回調介面中的recordEnd方法。
3.在這裡為了適應不同的錄音需求,我使用了策略模式來進行處理,將每一個不同的錄音方法視為一種不同的策略,根據自己的需要去改寫。

注意問題

1.在onTouchEvent的傳回值中應該返回true,這樣才能屏蔽之後其他的觸摸事件,否則當手指滑動離開Button之後將不能在響應我們的觸摸方法。
2.不要忘記為自己的App添加許可權:

            
代碼參考

RecordButton 類,我們的自訂控制項,重新複寫了onTouchEvent方法

package com.example.recordtest;import android.annotation.SuppressLint;import android.app.Dialog;import android.content.Context;import android.os.Handler;import android.os.Message;import android.util.AttributeSet;import android.view.Gravity;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 android.widget.Toast;public class RecordButton extends Button {    private static final int MIN_RECORD_TIME = 1; // 最短錄音時間,單位秒    private static final int RECORD_OFF = 0; // 不在錄音    private static final int RECORD_ON = 1; // 正在錄音    private Dialog mRecordDialog;    private RecordStrategy mAudioRecorder;    private Thread mRecordThread;    private RecordListener listener;    private int recordState = 0; // 錄音狀態    private float recodeTime = 0.0f; // 錄音時間長度,如果錄音時間太短則錄音失敗    private double voiceValue = 0.0; // 錄音的音量值    private boolean isCanceled = false; // 是否取消錄音    private float downY;    private TextView dialogTextView;    private ImageView dialogImg;    private Context mContext;    public RecordButton(Context context) {        super(context);        // TODO Auto-generated constructor stub        init(context);    }    public RecordButton(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        // TODO Auto-generated constructor stub        init(context);    }    public RecordButton(Context context, AttributeSet attrs) {        super(context, attrs);        // TODO Auto-generated constructor stub        init(context);    }    private void init(Context context) {        mContext = context;        this.setText(按住 說話);    }    public void setAudioRecord(RecordStrategy record) {        this.mAudioRecorder = record;    }    public void setRecordListener(RecordListener listener) {        this.listener = listener;    }    // 錄音時顯示Dialog    private void showVoiceDialog(int flag) {        if (mRecordDialog == null) {            mRecordDialog = new Dialog(mContext, R.style.Dialogstyle);            mRecordDialog.setContentView(R.layout.dialog_record);            dialogImg = (ImageView) mRecordDialog                    .findViewById(R.id.record_dialog_img);            dialogTextView = (TextView) mRecordDialog                    .findViewById(R.id.record_dialog_txt);        }        switch (flag) {        case 1:            dialogImg.setImageResource(R.drawable.record_cancel);            dialogTextView.setText(鬆開手指可取消錄音);            this.setText(鬆開手指 取消錄音);            break;        default:            dialogImg.setImageResource(R.drawable.record_animate_01);            dialogTextView.setText(向上滑動可取消錄音);            this.setText(鬆開手指 完成錄音);            break;        }        dialogTextView.setTextSize(14);        mRecordDialog.show();    }    // 錄音時間太短時Toast顯示    private void showWarnToast(String toastText) {        Toast toast = new Toast(mContext);        View warnView = LayoutInflater.from(mContext).inflate(                R.layout.toast_warn, null);        toast.setView(warnView);        toast.setGravity(Gravity.CENTER, 0, 0);// 起點位置為中間        toast.show();    }    // 開啟錄音計時線程    private void callRecordTimeThread() {        mRecordThread = new Thread(recordThread);        mRecordThread.start();    }    // 錄音Dialog圖片隨錄音音量大小切換    private void setDialogImage() {        if (voiceValue < 600.0) {            dialogImg.setImageResource(R.drawable.record_animate_01);        } else if (voiceValue > 600.0 && voiceValue < 1000.0) {            dialogImg.setImageResource(R.drawable.record_animate_02);        } else if (voiceValue > 1000.0 && voiceValue < 1200.0) {            dialogImg.setImageResource(R.drawable.record_animate_03);        } else if (voiceValue > 1200.0 && voiceValue < 1400.0) {            dialogImg.setImageResource(R.drawable.record_animate_04);        } else if (voiceValue > 1400.0 && voiceValue < 1600.0) {            dialogImg.setImageResource(R.drawable.record_animate_05);        } else if (voiceValue > 1600.0 && voiceValue < 1800.0) {            dialogImg.setImageResource(R.drawable.record_animate_06);        } else if (voiceValue > 1800.0 && voiceValue < 2000.0) {            dialogImg.setImageResource(R.drawable.record_animate_07);        } else if (voiceValue > 2000.0 && voiceValue < 3000.0) {            dialogImg.setImageResource(R.drawable.record_animate_08);        } else if (voiceValue > 3000.0 && voiceValue < 4000.0) {            dialogImg.setImageResource(R.drawable.record_animate_09);        } else if (voiceValue > 4000.0 && voiceValue < 6000.0) {            dialogImg.setImageResource(R.drawable.record_animate_10);        } else if (voiceValue > 6000.0 && voiceValue < 8000.0) {            dialogImg.setImageResource(R.drawable.record_animate_11);        } else if (voiceValue > 8000.0 && voiceValue < 10000.0) {            dialogImg.setImageResource(R.drawable.record_animate_12);        } else if (voiceValue > 10000.0 && voiceValue < 12000.0) {            dialogImg.setImageResource(R.drawable.record_animate_13);        } else if (voiceValue > 12000.0) {            dialogImg.setImageResource(R.drawable.record_animate_14);        }    }    // 錄音線程    private Runnable recordThread = new Runnable() {        @Override        public void run() {            recodeTime = 0.0f;            while (recordState == RECORD_ON) {                {                    try {                        Thread.sleep(100);                        recodeTime += 0.1;                        // 擷取音量,更新dialog                        if (!isCanceled) {                            voiceValue = mAudioRecorder.getAmplitude();                            recordHandler.sendEmptyMessage(1);                        }                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        }    };    @SuppressLint(HandlerLeak)    private Handler recordHandler = new Handler() {        @Override        public void handleMessage(Message msg) {            setDialogImage();        }    };    @Override    public boolean onTouchEvent(MotionEvent event) {        // TODO Auto-generated method stub        switch (event.getAction()) {        case MotionEvent.ACTION_DOWN: // 按下按鈕            if (recordState != RECORD_ON) {                showVoiceDialog(0);                downY = event.getY();                if (mAudioRecorder != null) {                    mAudioRecorder.ready();                    recordState = RECORD_ON;                    mAudioRecorder.start();                    callRecordTimeThread();                }            }            break;        case MotionEvent.ACTION_MOVE: // 滑動手指            float moveY = event.getY();            if (downY - moveY > 50) {                isCanceled = true;                showVoiceDialog(1);            }            if (downY - moveY < 20) {                isCanceled = false;                showVoiceDialog(0);            }            break;        case MotionEvent.ACTION_UP: // 鬆開手指            if (recordState == RECORD_ON) {                recordState = RECORD_OFF;                if (mRecordDialog.isShowing()) {                    mRecordDialog.dismiss();                }                mAudioRecorder.stop();                mRecordThread.interrupt();                voiceValue = 0.0;                if (isCanceled) {                    mAudioRecorder.deleteOldFile();                } else {                    if (recodeTime < MIN_RECORD_TIME) {                        showWarnToast(時間太短  錄音失敗);                        mAudioRecorder.deleteOldFile();                    } else {                        if (listener != null) {                            listener.recordEnd(mAudioRecorder.getFilePath());                        }                    }                }                isCanceled = false;                this.setText(按住 說話);            }            break;        }        return true;    }    public interface RecordListener {        public void recordEnd(String filePath);    }}

Dialog布局:

        

錄音時間太短的Toast布局:

        

自訂的Dialogstyle,對話方塊樣式

RecordStrategy 錄音策略介面

package com.example.recordtest;/** * RecordStrategy 錄音策略介面 * @author acer */public interface RecordStrategy {    /**     * 在這裡進行錄音準備工作,重設錄音檔案名稱等     */    public void ready();    /**     * 開始錄音     */    public void start();    /**     * 錄音結束     */    public void stop();    /**     * 錄音失敗時刪除原來的舊檔案     */    public void deleteOldFile();    /**     * 擷取錄音音量的大小     * @return      */    public double getAmplitude();    /**     * 返回錄音檔案完整路徑     * @return     */    public String getFilePath();}

個人寫的一個錄音實踐策略

package com.example.recordtest;import java.io.File;import java.io.IOException;import java.text.SimpleDateFormat;import java.util.Date;import android.media.MediaRecorder;import android.os.Environment;public class AudioRecorder implements RecordStrategy {    private MediaRecorder recorder;    private String fileName;    private String fileFolder = Environment.getExternalStorageDirectory()            .getPath() + /TestRecord;    private boolean isRecording = false;    @Override    public void ready() {        // TODO Auto-generated method stub        File file = new File(fileFolder);        if (!file.exists()) {            file.mkdir();        }        fileName = getCurrentDate();        recorder = new MediaRecorder();        recorder.setOutputFile(fileFolder + / + fileName + .amr);        recorder.setAudioSource(MediaRecorder.AudioSource.MIC);// 設定MediaRecorder的音頻源為麥克風        recorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);// 設定MediaRecorder錄製的音頻格式        recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);// 設定MediaRecorder錄製音訊編碼為amr    }    // 以目前時間作為檔案名稱    private String getCurrentDate() {        SimpleDateFormat formatter = new SimpleDateFormat(yyyy_MM_dd_HHmmss);        Date curDate = new Date(System.currentTimeMillis());// 擷取目前時間        String str = formatter.format(curDate);        return str;    }    @Override    public void start() {        // TODO Auto-generated method stub        if (!isRecording) {            try {                recorder.prepare();                recorder.start();            } catch (IllegalStateException e) {                // TODO Auto-generated catch block                e.printStackTrace();            } catch (IOException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }            isRecording = true;        }    }    @Override    public void stop() {        // TODO Auto-generated method stub        if (isRecording) {            recorder.stop();            recorder.release();            isRecording = false;        }    }    @Override    public void deleteOldFile() {        // TODO Auto-generated method stub        File file = new File(fileFolder + / + fileName + .amr);        file.deleteOnExit();    }    @Override    public double getAmplitude() {        // TODO Auto-generated method stub        if (!isRecording) {            return 0;        }        return recorder.getMaxAmplitude();    }    @Override    public String getFilePath() {        // TODO Auto-generated method stub        return fileFolder + / + fileName + .amr;    }}

MainActivity

package com.example.recordtest;import android.os.Bundle;import android.app.Activity;import android.view.Menu;public class MainActivity extends Activity {    RecordButton button;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        button = (RecordButton) findViewById(R.id.btn_record);        button.setAudioRecord(new AudioRecorder());    }    @Override    public boolean onCreateOptionsMenu(Menu menu) {        // Inflate the menu; this adds items to the action bar if it is present.        getMenuInflater().inflate(R.menu.main, menu);        return true;    }}
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.