播放媒体的来源可以来自源文件、文件系统或网络的数据流(URL)。
只能在标准的输出设备上播放音频,输出设备指的是移动设备上扬声器或蓝牙耳机,不可以从电话的话筒播放音频。一般而言,移动手机会有播放音乐用的扬声器和通话用的话筒。
这里我们主要使用MediaPlayer来实现音频及视频的播放功能。下面来介绍一下MediaPlayer的常用方法(表1)及监听事件(表2)。
表1 MediaPlayer的常用方法
方法 |
描述 |
create(Context context, Uri uri) |
静态方法,通过Uri创建一个多媒体播放器 |
create(Context context, int resid) |
静态方法,通过资源ID创建一个多媒体播放器 |
create(Context context, Uri uri, SurfaceHolder holder) |
静态方法,通过Uri和指定 SurfaceHolder 【抽象类】 创建一个多媒体播放器 |
getCurrentPosition() |
返回 Int, 得到当前播放位置 |
getDuration() |
返回 Int,得到文件的时间 |
getVideoHeight() |
返回 Int ,得到视频的高度 |
getVideoWidth() |
返回 Int,得到视频的宽度 |
isLooping() |
返回 boolean ,是否循环播放 |
isPlaying() |
返回 boolean,是否正在播放 |
pause() |
无返回值 ,暂停 |
prepare() |
无返回值,准备同步 |
prepareAsync() |
无返回值,准备异步 |
release() |
无返回值,释放 MediaPlayer 对象 |
reset() |
无返回值,重置 MediaPlayer 对象 |
seekTo(int msec) |
无返回值,指定播放的位置(以毫秒为单位的时间) |
setAudioStreamType(int streamtype) |
无返回值,指定流媒体的类型 |
setDataSource(String path) |
无返回值,设置多媒体数据来源【根据 路径】 |
setDataSource(FileDescriptor fd, long offset, long length) |
无返回值,设置多媒体数据来源【根据 FileDescriptor】 |
setDataSource(FileDescriptor fd) |
无返回值,设置多媒体数据来源【根据 FileDescriptor】 |
setDataSource(Context context, Uri uri) |
无返回值,设置多媒体数据来源【根据 Uri】 |
setDisplay(SurfaceHolder sh) |
无返回值,设置用 SurfaceHolder 来显示多媒体 |
setLooping(boolean looping) |
无返回值,设置是否循环播放 |
setScreenOnWhilePlaying(boolean screenOn) |
无返回值,设置是否使用 SurfaceHolder 显示 |
setVolume(float leftVolume, float rightVolume) |
无返回值,设置音量 |
start() |
无返回值,开始播放 |
stop() |
无返回值,停止播放 |
表2 MediaPlayer的监听事件
事件 |
描述 |
setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener listener) |
网络流媒体的缓冲监听 |
setOnCompletionListener(MediaPlayer.OnCompletionListener listener) |
网络流媒体播放结束监听 |
setOnErrorListener(MediaPlayer.OnErrorListener listener) |
设置错误信息监听 |
setOnVideoSizeChangedListener(MediaPlayer.OnVideoSizeChangedListener listener) |
视频尺寸监听 |
1 从源文件中播放
使用MediaPlayer类播放音频及视频,简单的一种方式就是从源文件中播放。要实现该功能需要以下步骤。
□ 将Android支持的媒体文件放在项目的res/raw文件夹下,如一个MP3文件,Eclipse开发环境的内置功能会发现这个文件,并将它生成一个信息,可以自R类引用到这个文件。
□ 创建一个MediaPlayer实例,可以使用MediaPlayer的静态方法create来完成,读出媒体资源。
□ 调用MediaPlayer实例的start()方法开始播放,调用stop()方法停止播放,调用pause()方法暂停播放,如暂停后再播放,需再次调用start()方法。如果希望重复播放,在调用start()方法之前,必须调用reset()和prepare()方法。
播放流程如图8-1所示。

图8-1 播放流程
程序代码如代码清单1所示。
代码清单1 播放源文件中视频或音频方法
//实例化MediaPlayer
MediaPlayer mMediaPlayer = MediaPlayer.create(this,R.raw.test);
MediaPlayer//开始播放
MediaPlayermMediaPlayer.start();
由上述可知,从源文件中播放是放在“<工程>/res/raw”,然后发布的时候被打成APK包一起安装在手机上。很显然这种方式不适合用于播放娱乐为主的多媒体文件,由于娱乐的多媒体文件是经常更新的,而放置在这个raw下面的文件用户是没有权限更新的,因此这种方式一般用于应用自己的一些音频和视频播放,如按键音、开机启动音、信息提示音等应用使用的声音。
2 从文件系统中播放
从文件系统中播放也是比较常见的一种方式。例如,在SD卡中有一些音频及视频文件,那么就可以直接进行播放。
从文件系统中播放需要以下步骤。
□ 实例化一个MediaPlayer。
□ 调用setDataSource()方法来设置想要播放文件的路径,取得播放的媒体文件。
□ 首先调用prepare(),然后调用start()来进行播放。
播放流程如图2所示。

图2 从文件系统中播放音频视频的播放流程
程序代码如代码清单2所示。
代码清单2 从文件系统中播放音频或视频
private void play() {
File sdCardDir = Environment.getExternalStorageDirectory();
//播放路径
String path = sdCardDir.getPath() + “/Lover’s Concerto.mp3”;
try {
if (mMediaPlayer == null || state == STOP) {
// 创建MediaPlayer对象并设置Listener
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setOnPreparedListener(preListener);
} else {
// 复用MediaPlayer对象
mMediaPlayer.reset();
}
//为MediaPlayer设置数据源
mMediaPlayer.setDataSource(path);
mMediaPlayer.prepare();
mMediaPlayer.start();
} catch (Exception e) {
e.printStackTrace();
}
}
从源文件中播放音频视频和从本地文件系统中播放音频视频的差别就在于play()方法中的mMediaPlayer = new MediaPlayer(),而不是MediaPlayer.Create(),然后设置预处理监听器,设置setDataSource(path),其中的path是指定的音频文件,这里放置SD卡中的MP3文件,mMediaPlayer.prepare()开始预处理。
3 从网络中播放
随着3G的不断完善和推广,自费不断降低,直接利用网络资源已经不是什么问题。移动互联网时代已经到了。这里就看一看如何通过网络来播放音视频文件。
要实现该功能有两种方法。
1.方法一
□ 创建网络URI实例。
□ 创建一个MediaPlayer实例,通过传递URI参数,使用MediaPlayer静态方法create完成。
□ 调用start()方法开始播放。
程序代码如代码清单3所示。
代码清单3从网络中播放音频或视频方法一
private void play() {
try {
//播放路径
String path =
"//ms1.m.mop.com/2008/08/27/012/12198150127399164.mp3";
//将字符串Uri解析为Uri实例
Uri uri = Uri.parse(path);
//实例化MediaPlayer
MediaPlayer player = MediaPlayer.create(this,uri);
//播放
player.start();
} catch (Exception e) {
e.printStackTrace();
}
}
2.方法二
□ 实例化一个MediaPlayer。
□ 调用setDataSource()方法来设置想要播放文件的路径,该路径是网络上的可用路径。
□ 首先调用prepare(),然后调用start()来进行播放。
程序代码如代码清单4所示。
代码清单4 从网络中播放音频或视频方法二
private void play() {
try {
//实例化MediaPlayer
MediaPlayer mp = new MediaPlayer();
//播放路径
String path =
"//ms1.m.mop.com/2008/08/27/012/12198150127399164.mp3";
try{
//设置数据源
mp.setDataSource(path);
//准备
mp.prepare();
//播放
mp.start();
}catch(IllegalArgumentException e){
e.printStackTrace();
}catch(IllegalStateException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
虽然从网络中播放音频视频不用存储比较方便,但它的弊端就是要通过网络,速度要比从源文件中和从文件系统中播放两种方式慢,因此上述两种播放方式中,利用同步预处理方法prepare()播放网络文件用户体验不好。一般网络播放方式要采用异步预处理方式。还有网络流量费用也会增加用户的使用成本。
播放流程如图3所示。

图3 从网络中播放音频视频流程图
程序代码如代码清单5所示。
代码清单5 从网络中播放音频或视频——异步处理方式
private void play() {
try {
if (mMediaPlayer == null || state == STOP) {
// 创建MediaPlayer对象并设置Listener
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setOnPreparedListener(preListener);
} else {
// 复用MediaPlayer对象
mMediaPlayer.reset();
}
// 播放网络媒体好不要调用prepare()方法
mMediaPlayer
.setDataSource ("//ms1.m.mop.com/2008/08/27/012/12198150127399164.mp3");
mMediaPlayer.prepareAsync();
} catch (Exception e) {
e.printStackTrace();
}
}