12.2.2 Android音视频的播放

在Android中,播放各类音视频流最简单的方式就是使用android.media.MediaPlayer对象,基本编码模式如下:


MediaPlayer mediaPlayer=new MediaPlayer();

//设置需要播放的文件

mediaPlayer.setDataSource(aMediaFile);

//播放文件

mediaPlayer.prepare();

mediaPlayer.start();


其中,MediaPlayer.setDataSource函数用来设置来自不同数据源的音视频流,比如:存放在资源文件中的音视频信息,存储在扩展存储器中的音视频文件,来自网络的音视频流等:


//播放扩展存储器中的音视频文件

mediaPlayer.setDataSource(A_FILE_IN_SDCARD);

//播放在来自网络的音视频内容

mediaPlayer.setDataSource(this,"http://a_sample_audio");

//播放存放在资源文件中的音视频信息

MediaPlayer mediaPlayer=MediaPlayer.create(this,

R.raw.a_sample_audio);

mediaPlayer.start();


小贴士 使用MediaPlayer播放来自于网络的音视频信息,必须要求该音视频是信息流格式的而不能是数据块格式的,否则,只能够先行下载到本地扩展存储设备中再进行播放。

对于开发者而言,控制音视频播放的重点在于理解音视频播放的状态信息。如图12-3所示,当MediaPlayer.setDataSource函数被调用后,音视频播放进入Initialized状态,在此状态下,系统还未读取音视频数据,需要调用MediaPlayer.prepare函数,使MediaPlayer进入Prepared的状态才能开始进行播放。当音视频开始播放后,可以调用MediaPlayer.pause函数暂停播放,抑或使用MediaPlayer.stop函数停止播放。

12.2.2 Android音视频的播放 - 图1

图 12-3 MediaPlayer的状态转移图

MediaPlayer在各个状态进行切换时都有可能需要花费较长时间(尤其涉及播放网络数据时),从而导致所在线程暂时阻塞。因此,如果开发者期望在主线程中进行音视频的播放,则需要使用MediaPlayer的异步操作接口。比如,使用MediaPlayer.prepareAsync函数来替换MediaPlayer.prepare函数:


MediaPlayer mediaPlayer=new MediaPlayer();

mediaPlayer.setDataSource(aMediaFile);

//设置监听对象,等待通知

mediaPlayer.setOnPreparedListener(new OnPreparedListener(){

void onPrepared(MediaPlayer mp){

mp.start();

}

});

//准备异步播放

mediaPlayer.prepareAsync();


使用异步播放模型,能够更充分地控制音视频的状态;但同时,它也引入了更为复杂的播放状态,使得开发变得更为繁琐。因此,如果开发者仅需要简单地播放音视频信息,可以考虑在独立的线程中用同步模式进行编程,降低开发的复杂度。在Android的原生应用中有比较复杂的音视频需求的应用,比如彩信应用、录音应用等,都会使用异步模式来进行音频播放;而在一些对音视频处理相对简单的应用,比如闹钟应用,则会采取同步模式进行播放。

MediaPlayer在播放完成后,会释放掉载入到内存中的音视频信息,降低内存占用。这对于一次性的音视频播放场景是合理的,但对于需要反复播放的音效文件而言,则显得不够合理,会造成额外的时间开销。因此,Android提供了android.media.SoundPool类,用来处理需要反复播放的音效信息。SoundPool会将这些需要播放的音视频信息保存在内存中,不再反复地从文件中读取,以此来加速播放流程。比如,当Android系统启动完成后,Android核心的音频管理服务就会初始化一个SoundPool,将所有需要使用的实例音频都添加进去,这样,当用户选择各种铃声、播放通知的提示音时,响应就更为迅速了。