MediaRecorder 录音,仿微信录音界面效果

封装MediaRecorder录音工具类,实现微信录音效果,如图:

 

xml文件布局

 

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.example.recordervoice.MainActivity"
    tools:showIn="@layout/activity_main">

    <ImageView
        android:id="@+id/image_say"
        android:src="@drawable/mic_1"
        android:visibility="gone"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/text_up_cancel"
        android:visibility="gone"
        android:layout_below="@id/image_say"
        android:textColor="@android:color/white"
        android:layout_centerHorizontal="true"
        android:textSize="14sp"
        android:layout_marginTop="-25dp"
        android:text="手指上滑,取消发送"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />


    <Button
        android:id="@+id/btn_say"
        android:background="@drawable/select_say_btn"
        android:layout_alignParentBottom="true"
        android:text="@string/pressed_say"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />


</RelativeLayout>

 

 

录音工具类

 

/**
 * Created by epdc on 2016/5/19.
 * 录音工具类
 */
public class RecorderVoiceUtil {

    public static String TAG = "epdc";

    private static MediaRecorder mediaRecorder;
    private static OnRecorderListener mListener;
    private static String mOutputPath;
    private static int mMaxDurationMs;
    private static long startRecorderTime, endRecorderTime;

    /**
     * 开始录音
     * @param outputPath
     * @param maxDurationMs 录音最大时间
     * @param listener
     */
    public static void startRecorder(String outputPath, final int maxDurationMs, final OnRecorderListener listener) {

        mListener = listener;
        mOutputPath = outputPath;
        mMaxDurationMs = maxDurationMs;

        mediaRecorder = new MediaRecorder();

        mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
        mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);

        if (mMaxDurationMs <= 0) {
            mediaRecorder.setMaxDuration(mMaxDurationMs);
        }
        mediaRecorder.setOutputFile(mOutputPath);
        //第一次获取为0
        mediaRecorder.getMaxAmplitude();
        mediaRecorder.setOnInfoListener(new MediaRecorder.OnInfoListener() {
            @Override
            public void onInfo(MediaRecorder mr, int what, int extra) {
                if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
                    mListener.onReachMax(mOutputPath, mMaxDurationMs);
                    stopRecorder();
                }
            }
        });

        mediaRecorder.setOnErrorListener(new MediaRecorder.OnErrorListener() {
            @Override
            public void onError(MediaRecorder mr, int what, int extra) {
                Log.e(TAG, "recorder error");
                mListener.onError();
            }
        });

        try {
            mediaRecorder.prepare();
        } catch (IOException e) {
            e.printStackTrace();
            Log.e(TAG, "recorder io error");
            mListener.onError();
            clear();
        }

        try {
            mediaRecorder.start();
            startRecorderTime = System.currentTimeMillis();
            Log.i(TAG, "recorder start");
            mListener.onStart();
        } catch (RuntimeException e) {
            e.printStackTrace();
            //没有录音权限报错,6.0以下版本应该是这样
            Log.e(TAG, "recorder permission error");
            mListener.onPermissionError();
        }
    }

    public static int getMaxAmplitude(){
        return mediaRecorder.getMaxAmplitude();
    }

    /**
     * 停止录音
     */
    public static void stopRecorder() {
        clear();
        endRecorderTime = System.currentTimeMillis();
        Log.i(TAG, "recorder success");
        Log.i(TAG, "recorder voiceLength:"+(endRecorderTime - startRecorderTime));
        mListener.onSuccess(mOutputPath, (endRecorderTime - startRecorderTime));
    }

    /**
     * 取消录音
     */
    public static void cancelRecorder() {
        clear();
        File file = new File(mOutputPath);
        file.delete();
        Log.w(TAG, "recorder cancel");
        mListener.onCancel();
    }

    /**
     * 释放资源
     */
    private static void clear(){
        //start后,一秒内stop录音会报RuntimeException
        try {
            mediaRecorder.stop();
        } catch (RuntimeException e){
            e.printStackTrace();
        }

        mediaRecorder.release();
        mediaRecorder = null;
    }


    public interface OnRecorderListener {
        void onReachMax(String outputPath, int maxDurationMs);

        void onError();

        void onPermissionError();

        void onStart();

        void onCancel();

        void onSuccess(String outputPath, long voiceLength);
    }

    public static class SimpleRecorderListener implements OnRecorderListener {

        @Override
        public void onReachMax(String outputPath, int maxDurationMs) {

        }

        @Override
        public void onError() {

        }

        @Override
        public void onPermissionError() {

        }

        @Override
        public void onStart() {

        }

        @Override
        public void onCancel() {

        }

        @Override
        public void onSuccess(String outputPath, long voiceLength) {

        }
    }

}

 

 

线程类,根据录音时声音大小更新界面

 

public class RecorderTask extends TimerTask {

    public static String TAG = "epdc";
    
    private final ImageView imageSay;
    private Activity activity;
    private boolean isCancel;

    public RecorderTask(Activity activity, ImageView imageSay) {
        this.activity = activity;
        this.imageSay = imageSay;
    }

    @Override
    public void run() {

        if (!isCancel){
            int maxAmplitude = RecorderVoiceUtil.getMaxAmplitude();
            Log.i(TAG, "maxAmplitude为:" + maxAmplitude);
            if (maxAmplitude > 1) {
                final double db = 20 * Math.log10(maxAmplitude);
                Log.i(TAG, "音量为:" + db);
                Log.i(TAG, "imageSay:" + imageSay+", isCancel"+isCancel);
                if (imageSay != null && !isCancel) {
                    activity.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            if (db <= 15) {
                                imageSay.setImageResource(R.drawable.mic_1);
                            } else if (db > 15 && db <= 30) {
                                imageSay.setImageResource(R.drawable.mic_2);
                            } else if (db > 30 && db <= 45) {
                                imageSay.setImageResource(R.drawable.mic_3);
                            } else if (db > 45 && db <= 60) {
                                imageSay.setImageResource(R.drawable.mic_4);
                            } else if (db > 60 && db <= 75) {
                                imageSay.setImageResource(R.drawable.mic_5);
                            } else if (db > 75) {
                                imageSay.setImageResource(R.drawable.mic_6);
                            }
                        }
                    });

                }
            }
        }

    }

    public boolean isCancel() {
        return isCancel;
    }

    public void setCancel(boolean cancel) {
        isCancel = cancel;
    }
}

分贝计算参考链接http://blog.csdn.net/greatpresident/article/details/38402147
MainActivity的实现

 

 

/**
 * Created by epdc on 2016/5/19.
 */
public class MainActivity extends AppCompatActivity {

    String tag = "epdc";

    Button btnSay;
    ImageView imageSay;
    TextView textUpCancel;

    Context context;
    GestureDetector gestureDetector;
    RecorderVoiceUtil.OnRecorderListener recorderListener;
    boolean isCancel;
    private RecorderTask recorderTask;
    private Timer recorderTime;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        context = this;

        btnSay = (Button) findViewById(R.id.btn_say);
        imageSay = (ImageView) findViewById(R.id.image_say);
        textUpCancel = (TextView) findViewById(R.id.text_up_cancel);

        recorderListener = new RecorderVoiceUtil.SimpleRecorderListener(){
            @Override
            public void onPermissionError() {
                super.onPermissionError();
                Toast.makeText(context, "没有录音权限", Toast.LENGTH_LONG).show();
            }

            @Override
            public void onReachMax(String outputPath, int maxDurationMs) {
                super.onReachMax(outputPath, maxDurationMs);
                cancelRecorder();
            }

            @Override
            public void onError() {
                super.onError();
                cancelRecorder();
            }
        };


        gestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener(){
            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                Log.i(tag, "onScroll distanceY:"+distanceY);
                if (distanceY >= 10) {
                    btnSay.setText(R.string.up_finger_finish);
                    textUpCancel.setVisibility(View.GONE);
                    imageSay.setImageResource(R.drawable.mic_cancel);
                    //线程没有结束,只是不让更新界面
                    recorderTask.setCancel(true);
                    isCancel = true;
                }

                if (distanceY <= -10) {
                    btnSay.setText(R.string.up_finish);
                    textUpCancel.setVisibility(View.VISIBLE);
                    imageSay.setImageResource(R.drawable.mic_1);
                    recorderTask.setCancel(false);
                    isCancel = false;
                }
                return true;
            }

            @Override
            public boolean onDown(MotionEvent e) {
                Log.i(tag, "onDown");
                startRecorder();
                return true;
            }
        });


        btnSay.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {

                boolean flag = gestureDetector.onTouchEvent(event);
                if (flag) {
                    return true;
                }

                switch (event.getAction()) {
                    case MotionEvent.ACTION_UP:
                        flag = true;
                        stopRecorder();
                        break;
                    case MotionEvent.ACTION_CANCEL:
                        cancelRecorder();
                        flag = true;
                        break;
                }

                return flag;
            }
        });
    }

    private void startRecorder() {
        btnSay.setSelected(true);
        btnSay.setText(R.string.up_finish);
        textUpCancel.setVisibility(View.VISIBLE);
        imageSay.setVisibility(View.VISIBLE);

        String filename = "recordvoice" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + ".mp3";
        RecorderVoiceUtil.startRecorder(FileUtil.getPathOfMusic(context, filename), 60 * 1000, recorderListener);

        recorderTime = new Timer();
        recorderTask = new RecorderTask(this, imageSay);
        recorderTime.schedule(recorderTask, 0, 200);
    }

    private void stopRecorder(){
        btnSay.setSelected(false);
        btnSay.setText(R.string.pressed_say);
        textUpCancel.setVisibility(View.GONE);
        imageSay.setVisibility(View.GONE);

        recorderTask.setCancel(true);
        recorderTime.cancel();

        if (isCancel) {
            Log.i(tag, "up 取消录音");
            RecorderVoiceUtil.cancelRecorder();
        } else {
            RecorderVoiceUtil.stopRecorder();
        }
    }

    private void cancelRecorder(){
        Log.i(tag, "cancel 取消录音");
        btnSay.setSelected(false);
        textUpCancel.setVisibility(View.GONE);
        imageSay.setVisibility(View.GONE);
        btnSay.setText(R.string.pressed_say);

        recorderTask.setCancel(true);
        recorderTime.cancel();
    }
}


源代码下载

https://download.csdn.net/download/epdc2/9527241

 

 

 

 

 

 

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值