前言
录音机是大家手机里的常见应用程序。今天我们来设计一个简单的录音机应用,同时了解一下相关的Android知识。
开发工具
Android Studio 2.3.3
实现过程
界面设计
界面上设置了开始录音(停止录音)、播放录音(暂停播放)的Button,显示当前录音或播放时间的Textview和显示录音音量的ProgressBar。
活动的.xml文件是通过Android的约束布局(ConstraintLayout)编辑的,这种布局适合使用可视化的方式来编写界面,通过约束的方式来指定各个控件的位置和关系,可以有效地解决布局嵌套过多的问题。由于相应的代码会自动生成,这里就不展示代码了。
感兴趣的读者可以参考下面这篇文章,里面比较详细地讲解了约束布局的常见用法:http://blog.csdn.net/guolin_blog/article/details/53122387。
效果如图:
权限申请
程序运行前首先需要申请以下权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>)
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
分别表示调用麦克风和SD卡写入
其他功能
首先,在活动中添加控件
private ImageButton start;
private ImageButton play;
private TextView time;
private ImageView volume;
private ProgressBar progressBar;
主活动中还定义了如下变量:
private MediaRecorder mediaRecorder=new MediaRecorder(); //用于录音
private File file=new File("/mnt/sdcard","new.amr"); //创建一个临时的音频文件
private MediaPlayer mediaPlayer=new MediaPlayer(); //用于播放录音
private long currenttime; //用于确定当前录音时间
private boolean isrecording=false; //用于判断当前是否在录音
private boolean Isplaying=false; //用于判断是否正在处于播放录音状态
然后,在OnCreate()中进行初始化:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start=(ImageButton)findViewById(R.id.startButton);
play=(ImageButton)findViewById(R.id.playButton);
time=(TextView)findViewById(R.id.time);
volume=(ImageView)findViewById(R.id.volume);
progressBar=(ProgressBar)findViewById(R.id.progress);
start.setOnClickListener(this);
play.setOnClickListener(this);
mediaPlayer.setOnCompletionListener(playerListener);
}
除此之外,由于录音音量和录音/播放时间需要隔一段时间显示一次,需要在线程中调用相关方法,具体实现如下:
//定义Handler
private Handler volumehandler=new Handler(); //显示音量
private Handler timehandler=new Handler(); //显示录音时间
private Handler playhandler=new Handler(); //显示播放时间
private Runnable runnable_1=new Runnable() { //音量
@Override
public void run() {
int volume=0;
int ratio;
ratio = mediaRecorder.getMaxAmplitude() / 600;
if(ratio>1){
volume= (int) (20 * Math.log10(ratio));
} //将getMaxAmplitude()的返回值转换为分贝
progressBar.setMax(15);//将最大音量设置为60分贝
progressBar.setProgress(volume/4);//显示录音音量
volumehandler.postDelayed(runnable_1, 100);
}
};
private Runnable runnable_2=new Runnable() {//录音时间
@Override
public void run() {
time.setText(getTime((int) (System.currentTimeMillis()-currenttime)));
//调用前先获取当前时间,再通过System.currentTimeMillis()-currenttime获得录音时间并转换成文本
timehandler.postDelayed(runnable_2,1000);
}
};
private Runnable runnable_3=new Runnable() {//播放时间
@Override
public void run() {
time.setText(getTime(mediaPlayer.getCurrentPosition()));
//MediaPlayer类的getCurrentPosition()方法可以获得音频的当前播放时间
playhandler.postDelayed(runnable_3,1000);
}
};
这里getTime方法用于将一个毫秒值转换为“xx:xx”的文本,代码如下:
private String getTime(int timeMs) {
int total=timeMs/1000;
StringBuilder stringBuilder=new StringBuilder();
Formatter formatter=new Formatter(stringBuilder,Locale.getDefault());
int seconds=total%60;
int minutes=(total/60)%60;
int hours=total/3600;
stringBuilder.setLength(0);
if (hours>0){
return formatter.format("%d:%02d:%02d",hours,minutes,seconds).toString();
}
else{
return formatter.format("%02d:%02d",minutes,seconds).toString();
}
}
按钮逻辑
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.startButton:
if (isrecording) {
stop();
} else {
record();
}
break;
case R.id.playButton:
if(mediaPlayer.isPlaying()){
pause();
}
else{
play();
}
break;
default:
break;
}
}
录音是通过MediaRecorder类实现的,具体的录音和停止方法如下:
private void record(){
if(file.exists()) {
file.delete();
}
mediaRecorder.reset();
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
//设置音频来源为麦克风
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
//默认的输出格式和编码方式
mediaRecorder.setOutputFile(file.getAbsolutePath());//指定音频输出路径
try {
mediaRecorder.prepare();
} catch (IOException e) {
e.printStackTrace();
}
mediaRecorder.start();//开始录音
start.setImageResource(ic_media_pause);
isrecording=true;
currenttime=System.currentTimeMillis();
volumehandler.postDelayed(runnable_1,100);
timehandler.postDelayed(runnable_2,1000);
}
private void stop(){
mediaRecorder.stop();
start.setImageResource(btn_radio);
volumehandler.removeCallbacks(runnable_1);
timehandler.removeCallbacks(runnable_2);//停止相关线程
time.setText("00:00");
isrecording=false;
Toast.makeText(this,"录音完成!", Toast.LENGTH_SHORT).show();
}
播放/暂停音频是通过MediaPlayer类实现的,具体实现方法如下:
private void play(){
if(!Isplaying) {
if (file != null && file.exists()) {
try {
mediaPlayer.setDataSource(MainActivity.this, Uri.fromFile(file));//设置音频来源
} catch (IOException e) {
e.printStackTrace();
}
} else {
Toast.makeText(this, "未发现录音文件", Toast.LENGTH_SHORT).show();
return;
}
try {
mediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
Isplaying = true;
}
mediaPlayer.start();//开始播放
play.setImageResource(ic_media_pause);
playhandler.postDelayed(runnable_3,1000);
}
private void pause(){
mediaPlayer.pause();
playhandler.removeCallbacks(runnable_3);
play.setImageResource(ic_media_play);
}
设置OnCompletionListener监听音频播放完成:
MediaPlayer.OnCompletionListener playerListener = new MediaPlayer.OnCompletionListener(){
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
play.setImageResource(ic_media_play);
playhandler.removeCallbacks(runnable_3);
time.setText("00:00");
Isplaying=false;
mediaPlayer.reset();
}
};
可拓展处
实现用户自定义录音文件名称和保存路径、实现用户选择录音文件播放、界面进一步优化等。
个人总结
通过这次的小项目,学到了一些相关的知识。但是由于刚刚入门不久,这个项目的实现非常简单,有些地方也参考了别人的Demo,可以拓展的方面还有很多,接下来还需要更多的研究和学习。如果文章存在错误,欢迎读者批评指正。
谢谢大家!
网友评论