主要实现的功能大的类有两个:MediaPlayer和MediaRecorder类。功能描述:先通过录音程序录一段语音存放到手机SD卡的指定目录里,通过ListView显示录音文件内容,点击录音文件进入播放小程序,播放选中的录音文件播放、暂停、停止功能,中使用了Intent类实现两个Activity之间数据传递(录音文件路径)。
下面通过一个Samples10_2程序具体实现如上功能:
(1)新建一个Android Application Project项目取名为Samples10_2
(2)在res/layout文件修改activity_main.xml主布局文件(主要是添加两个按钮控件,录音和停止按钮):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<Button
android:id="@+id/re_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="录音" />
<Button
android:id="@+id/re_stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="停止" />
</LinearLayout>
<ListView
android:id="@+id/listView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
</ListView>
</LinearLayout>
(3)因为要显示录音文件内容,通过在res/layout目录下添加一个file_list.xml布局文件,来实现显示当前录音文件的功能:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/linearLayout1"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TextView
android:id="@+id/fileName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge" />
</LinearLayout>
(4)因为要实现录音内容的播放功能,在res/layout目录下添加一个play.xml布局文件(主要有三个按钮和一个显示标题的空间,播放、暂停、停止和程序标题):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<TextView
android:id="@+id/mp3_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge" />
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/play_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="播放" />
<Button
android:id="@+id/play_pause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="暂停" />
<Button
android:id="@+id/play_stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="停止" />
</LinearLayout>
</LinearLayout>
(5)首先需要给程序必要的权限才能读/写、录制音频文件、创建删除文件、(联网)等权限。在程序的AndroidManifest.xml程序清单文件下添加如下权限:
<!--录制音频文件权限 -->
<uses-permission android:name="android.permission.RECORD_AUDIO"></uses-permission>
<!-- 在SDCard中创建与删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!-- 往SDCard写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- 手机访问Internet权限 -->
<uses-permission android:name="android.permission.INTERNET" />
因为Play.java类是另一个Activity所以还需要在AndroidMainifest.xml文件中添加这样一段代码(一般这里的类名需要写完整的类结构):
<activity android:name=".Play"></activity>
(6)下面就是两个Activity实现布局文件调用和具体功能的实现:MainActivity.java类(录音功能)和Play类(播放功能):
A.MainActivity.java类的具体实现:
package com.example.samples_10_2;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.Button;
import android.widget.ListView;
import java.io.File;
import android.media.MediaRecorder;
import android.os.Environment;
import android.app.AlertDialog;
import android.content.DialogInterface;
import java.io.File;
import java.util.List;
import java.util.HashMap;
import java.util.ArrayList;
import android.widget.SimpleAdapter;
import android.view.View;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView;
import android.content.Intent;
import android.media.MediaRecorder;
import android.media.MediaRecorder.OnErrorListener;
public class MainActivity extends Activity {
private Button startButton=null;//播放Button组件对象
private Button stopButton=null;//停止播放Button组件对象
private ListView listView=null;//用于显示文件列表的ListView组件对象
private File[] files=null;//File数组
private String dirPath="";//文件读/写指定目录
private MediaRecorder mediaRecorder=null;//创建一个空的MediaRecorder对象
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startButton=(Button)this.findViewById(R.id.re_start);//实例化播放Button组件对象
stopButton=(Button)this.findViewById(R.id.re_stop);//实例化停止播放Button组件对象
listView=(ListView)this.findViewById(R.id.listView);//实例化ListView组件对象
stopButton.setEnabled(false); //停止按钮失效
setListViewData(); //为ListView填充数据
startButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
// 调用录音方法
startRecord();
}
});
stopButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
//调用停止录音方法
stopRecord();
}
});
listView.setOnItemClickListener(new OnItemClickListener() {
//为ListView添加单击监听 实现点击录音文件转跳到另一个程序的功能
@Override
public void onItemClick(AdapterView<?> arg0 , View arg1, int arg2, long arg3)
{
Intent intent=new Intent();//初始化Intent
intent.setClass(MainActivity.this, Play.class);//指定Intent对象启动的类
intent.putExtra("filePath", files[arg2].getPath());//函数传递
MainActivity.this.startActivity(intent);//启动新的Activity
}
});
}
/**
* 开始录音的方法
*/
public void startRecord()
{
//获取录音文件路径
String path=getRecordFilePath();//获取录音文件路径
if(!"".equals(path))
{
mediaRecorder=new MediaRecorder();//实例化MediaRecorder
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);//设置音频源
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);//设置输出格式
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);//设置音频编码器
mediaRecorder.setOutputFile(path);//设置输出路径
}
//文件录制错误监听
mediaRecorder.setOnErrorListener(new MediaRecorder.OnErrorListener() {
@Override
public void onError(MediaRecorder arg0, int arg1, int arg2) {
if(mediaRecorder!=null)
{
//解除资源与mediaRecorder的赋值关系,让资源可以为其他程序利用
mediaRecorder.release();
}
}
});
try
{
mediaRecorder.prepare();//准备
mediaRecorder.start();//开始录音
startButton.setEnabled(false);//录音按钮失效
stopButton.setEnabled(true);//停止按钮生效
startButton.setText("录音中…");
}catch(Exception e)
{
e.printStackTrace();
}
}
/**
* 停止录音的方法
*/
public void stopRecord()
{
if(mediaRecorder!=null)
{
mediaRecorder.stop();//停止录音
mediaRecorder.release();//释放资源
startButton.setEnabled(true);//录音按钮生效
startButton.setText("录音");
stopButton.setEnabled(false);//停止按钮失效
setListViewData();//录音完成重新为ListView填充数据
}
}
/**
* 获取录音文件的路径
* @return
*/
public String getRecordFilePath()
{
String filePath="";//声明文件路径
boolean sdCardState=getStorageState();//获取sdCard状态
if(!sdCardState)
{
return filePath;//返回空字符串路径
}
String sdCardPath=Environment.getExternalStorageDirectory().getPath();//获取sdCard根目录路径
File dirFile=new File(sdCardPath+File.separator+"recording");//自定义的录音文件File文件对象
if(!dirFile.exists())
{
dirFile.mkdir();//不存在创建文件夹
}
try
{
//创建一个前缀为test后缀为.amr的录音文件,使用createTempFile方法来创建是为了避免文件冲突
filePath=File.createTempFile("test",".amr",dirFile).getAbsolutePath();
}catch(Exception e)
{
e.printStackTrace();
}
return filePath;//返回录音文件路径
}
/*
* 为播放组件对象ListView填充数据
*/
public void setListViewData()
{
boolean sdStatus=getStorageState();//调用获取手机sdCard的存储状态
if(sdStatus)//判断sdCard的存储状态,如果是false提示并结束应用程序
{
File sdCardFile=Environment.getExternalStorageDirectory();//获取sdCard根目录File对象
dirPath=sdCardFile.getPath()+File.separator+"recording";//指定文件存放目录
File dirFile=new File(dirPath);
if(!dirFile.exists())//判断文件存放目录是否存在
{
dirFile.mkdir();//不存在创建存放目录
}
files=dirFile.listFiles();//获取文件存放目录中的文件File对象
List<HashMap<String,Object>> list=getList(files);//调用获取相应的集合
setAdapter(list,files);//调用构造适配器并为ListView添加适配器
}
}
/**
* 根据File[]获取相应的集合
* @param
* files File数组
* @return
* List<HashMap<String,Object>>
*/
public List<HashMap<String,Object>> getList(File[] files)
{
List<HashMap<String,Object>> list=new ArrayList<HashMap<String,Object>>();//创建List集合
for(int i=0;i<files.length;i++)//循环File数组
{
HashMap<String,Object> hashMap=new HashMap<String,Object>();//创建HashMap
hashMap.put("file_name", files[i].getName());//往HashMap中添加文件名
list.add(hashMap);//将HashMap添加到List集合中
}
return list;//返回List集合
}
/**
* 构造适配器,为ListView添加适配器
* @param list
* @param files
*/
public void setAdapter(List<HashMap<String,Object>> list,File[] files)
{
SimpleAdapter simpleAdapter=newSimpleAdapter(
this, //android.content.Context上下文
list, // java.util.List<? extends java.util.Map<java.lang.String, ?>>类型的List数据泛型
R.layout.file_list,//int 布局数据
new String[]{"file_name"},//java.lang.String[] 文件名称
new int[]{R.id.fileName});//int[] TextView的Id
listView.setAdapter(simpleAdapter);//为ListView添加适配器
}
/*
* 获取手机sd卡的存储状态
*/
public boolean getStorageState()
{
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))//判断手机sd卡的存储状态
{
return true;
}else
{
new AlertDialog.Builder(this)//创建AlertDialog对象
.setTitle("提示信息")//设置信息标题
.setMessage("未安装SD卡,请检查你的设备")//设置信息内容
.setPositiveButton("确认",new android.content.DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface arg0, int arg1) {
//结束应用程序
MainActivity.this.finish();
}
}).show();
return false;
}
}
}
B.Play类的具体实现:
package com.example.samples_10_2;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.media.MediaPlayer;
import android.view.View.OnClickListener;
import android.os.Environment;
import java.io.File;
import android.net.Uri;
import android.media.MediaPlayer.OnCompletionListener;
import android.content.Intent;
public class Play extends Activity {
private MediaPlayer mediaPlayer = null; // 创建一个空MediaPlayer对象
private Button startButton = null; // 播放Button组件对象
private Button pauseButton = null; // 暂停Button组件对象
private Button stopButton = null; // 停止Button组件对象
private TextView nameTextView = null; // 文件名称TextView组件对象
private boolean isPause = false; // 是否暂停
private String filePath=null;//保存播放文件的路径
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.play);
Intent intent=getIntent();
Bundle bundle=intent.getExtras();
filePath=bundle.get("filePath").toString();
nameTextView=(TextView)this.findViewById(R.id.mp3_name);//实例化文件名称TextView组件对象
nameTextView.setText(filePath); //设置文件名称
startButton=(Button)this.findViewById(R.id.play_start); //实例化播放Button组件对象
startButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// 调用Mp3播放方法
start();
}
});
pauseButton=(Button)this.findViewById(R.id.play_pause);//实例化暂停Button组件对象
pauseButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
//调用Mp3暂停方法
pause();
}
});
stopButton=(Button)this.findViewById(R.id.play_stop);//实例化停止播放组件对象
stopButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
// 调用Mp3停止播放方法
stop();
}
});
}
/**
* Mp3开始播放
*/
public void start()
{
try
{
if(mediaPlayer!=null)
{
if(mediaPlayer.isPlaying())//判断MediaPlayer对象正在播放中,并不执行一下程序
{
return;
}
}
stop(); //调用停止播放方法
if(isPause)//判断MediaPlayer对象是否暂停,如果暂停不重新播放
{
return;
}
// 加载资源文件中的MP3
/*mediaPlayer=MediaPlayer.create(this, R.raw.becauseoflove);//加载资源文件中的MP3
mediaPlayer.start();//开始播放
*/
//SD卡资源
mediaPlayer=new MediaPlayer();
mediaPlayer.setDataSource(filePath);
mediaPlayer.prepare();//准备播放
mediaPlayer.start();//播放
/*
* 网络资源
*/
/*mediaPlayer=new MediaPlayer();
String path="http://music.baidu.com/data/music/file?link=http://yinyueshiting.baidu.com/data2/music/3566287/29237101437253261128.mp3?xcode=fc3ef977c9fa9bdf4394f800f7f2550e&song_id=2923710";
Uri uri=Uri.parse(path);
mediaPlayer=MediaPlayer.create(this, uri);
mediaPlayer.setDataSource(path);//为MediaPlayer设置数据源
mediaPlayer.prepare();//准备播放
mediaPlayer.start();//开始播放
*/
//文件播放完毕监听
mediaPlayer.setOnCompletionListener(new android.media.MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer arg0) {
// 覆盖文件播出完毕事件
mediaPlayer.release();
startButton.setText("播放");
isPause=false;//取消暂停状态
mediaPlayer=null;
}
});
//文件播放错误监听
mediaPlayer.setOnErrorListener(new android.media.MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer arg0, int arg1, int arg2) {
//解除资源与MediaPlayer的赋值关系,让资源可以为其他程序利用
arg0.release();
return false;
}
});
startButton.setText("正在播放");
pauseButton.setText("暂停");
}catch(Exception e)
{
e.printStackTrace();
}
}
/*
* MP3暂停播放
*/
public void pause()
{
try
{
if(mediaPlayer!=null)//判断MediaPlayer对象不为空
{
if(mediaPlayer.isPlaying())//判断MediaPlayer对象正在播放中
{
mediaPlayer.pause();//暂停播放
pauseButton.setText("取消暂停");
isPause=true;//暂停状态
}else
{
mediaPlayer.start();//开始播放
pauseButton.setText("暂停");
isPause=false;
}
}
}catch(Exception e)
{
e.printStackTrace();
}
}
/*
* MP3停止播放
*/
public void stop()
{
try
{
if(mediaPlayer!=null)//判断MediaPlayer对象不为空
{
mediaPlayer.stop();//停止播放
startButton.setText("播放");
isPause=false;//取消暂停状态
mediaPlayer.release();
mediaPlayer=null;
}
}catch(Exception e)
{
e.printStackTrace();
}
}
}
(7)程序运行的结果如图所示:
A.打开录音的界面:
B.点击录音按钮界面:
C.点击停止录音按钮后界面:
D.多次点击录音停止按钮界面:
E.点击刚才录音的音频文件转跳到Play Activity类界面:
F.点击播放按钮显示界面:
G.点击暂停按钮显示界面:
H.点击停止播放按钮显示界面:
(8)代码程序具体详解:
两个Activity通过Intent类进行交互(使用到的Bundle类)
在MainActiviy.java类中使用如下代码:
Intent intent=new Intent();//初始化Intent
intent.setClass(MainActivity.this, Play.class);//指定Intent对象启动的类
intent.putExtra("filePath", files[arg2].getPath());//函数传递
MainActivity.this.startActivity(intent);//启动新的Activity
将录音文件的路径存入到Bundle中的key-value键值对,使用startActivity(intent)函数实现转跳。
在Play.java类中使用如下代码,接收传递过过来的Bundle键值对,代码如下:
Intent intent=getIntent();
Bundle bundle=intent.getExtras();
filePath=bundle.get("filePath").toString();
至此所有录音和播放功能都已经介绍完成了,需要注意两个问题一个是权限问题,一个是Activity之间赋值问题。