Android Media Playback 中的MediaPlayer的用法及注意事项(一)
声明:以下内容翻译自Android官网,由于译者水平有限,本文出现的错误请大家批评指正,谢谢!
尊重劳动成果,转载请注明出处,http://blog.csdn.net/u014532901/article/details/46580365,谢谢!
安卓多媒体框架对于播放各种各样的常见的媒体文件提供了支持,得益与此,我们可以在我们的应用程序中整合音频,视频和图像。我们使用android提供给我们的MediaPlayer的API,我们可以播放存放在应用程序中的文件(Raw Files),文件系统中的独立的文件,或者来自网络连接上的数据流文件。
注意:你仅仅可以在标准的输出设备中播放音频数据。目前常见的就是手机的扬声器,或者一个蓝牙耳机。另外,你并不能在打电话的时候去播放一个声音文件。
1.基本部分:
下面是在android框架中被用来播放音频视频的类
AudioManager:管理音频资源,和音频在设备上的输出;
3.Manifest声明
.Internet Permission 如果你想使用网络上的内容作为你的播放内容,你必须声明这个权限。
<span style="font-size:18px;"><uses-permission android:name="android.permission.INTERNET" />
</span>
.Wake Lock Permission 如果你的程序需要保持屏幕常亮,或者不让CPU休眠,那么你就必须声明这个权限
<uses-permission android:name="android.permission.WAKE_LOCK" />
3.使用MediaPlayer
在android多媒体框架中,MediaPlayer是最重要的组件之一。一个MediaPlayer的实例(或者称为对象)能够让我们使用最少的配置去获取、解码、播放音频和视频。它支持数种不同的资源如下所示:
- .本地资源(例如那些存放在你的程序包中raw目录下的文件)
- .内部的URI指向的资源,例如可以通过Content Resolver获取
- .外部的URL资源(流式文件)(SD卡上的、网络服务器上流式文件等等)
下面是一个关于如何播放一个存放为本地资源的音频文件,(存放在你的程序的res/raw/ 目录下面)
MediaPlayer mediaPlayer = MediaPlayer.create(context, R.raw.sound_file_1);
mediaPlayer.start(); // 用不着调用prepare()方法,creat()方法已经为我们完成了
在上面的例子中,对于"raw"资源文件, android不会试着用任何方式去解析它。正因为如此,这里面存放的资源不应该是一个原始的音频,它应该是一些适当编码、格式化的、格式被支持的媒体文件。
下面这个例子展示了如何播放可用的内部URI指向的资源。(你可以通过一个 Content Resolver实例去获取它)
Uri myUri = ....; // 你的uri的声明
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(getApplicationContext(), myUri);
mediaPlayer.prepare();mediaPlayer.start();
下面这个例子是通过HTTP协议播放一个远程的URL指向的流
String url = "http://www.baidu.com/music/GoBigOrGoHome.mp3"; //这里是你的URLMediaPlayer
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(url);mediaPlayer.prepare(); // 也许花费很长的时间,例如为了进行一些缓存的初始化
mediaPlayer.start();
注意:如果你传递的是一个指向在线的媒体文件的URL,这个文件必须是能够获取得到的。因此,你应该去捕获一些异常以防止你给的URL指向的文件可能根本就不存在。
4.异步准备
在原则上来说,使用 MediaPlayer是很直接简单的。但是需要记住的一点是,把 MediaPlayer正确的整合到我们的程序中,有一些额外的必要的事情是必须做的(但是这是 API做)。例如,因为可能涉及到获取、解码多媒体文件, MediaPlayer的 prepare()方法有时候会花费很长的时间来执行。所以,你不应该在你的 UI主线程中去调用它。因为这样会挂起你的 UI知道的这个方法返回,结果就是导致了非常差的用户体验,并可能引起 ANR的错误。即使你觉得没关系,我从本地加载资源是很快的,那么你也请注意,在 UI做任何超过耗时0.1秒的的操作都会引起一个明显的停顿(我觉得0.1秒都有点过长,不是说好的16ms吗?),结果给用户的感受是:这个程序很卡。
为了避免上述的情况的发生,应该创建另一个线程来准备这个 MediaPlayer,在准备工作做完后再去通知UI主线程。同时, android框架提供一个很方便的方法来完成这个准备的任务,这就是 prepareAsync()方法,这个方法在后台线程去完成 MediaPlayer准备的工作,在做完工作后立即返回。搭配使用的是应该自定义一个 实现了 MediaPlayer. OnPreparedListener接口的 onPrepared()方法的监听器,在调用prepareAsync()方法之前,通过 setOnPreparedListener()方法将 MediaPlayer注册给监听器,在异步准备工作完成后,系统会回调 onPrepared()方法。
5.管理MediaPlayer的状态
关于 MediPalyer另一个需要记住的方面就是 MediPlayer是基于状态的。这就是说, MediaPlayer有一个内部的状态,当你写你的代码时,你一直要记住这一点。因为你只能在对应的 MediaPlayer的状态下,去调用它 的对应的方法。就好比是你不应该让一个不会走路的婴儿去调用他去打篮球一样(译者注),如果你在错误的状态去调用了错误的方法,那么系统就会抛出异常或者程序直接崩掉。
下面是MediaPlayer的状态图,以及一些对应的方法在哪些状态可以被调用。
![](https://i-blog.csdnimg.cn/blog_migrate/19bbd9d2ecc2fa4790594f0cdaf8fbb0.gif)
因此在你对一个MediaPlayer对象操作的时候,时刻记住这张图,因为在错误的状态调用的方法会引发一个BUG.
6.释放MediaPlayer
MediaPlayer会消耗有用的系统资源。因此,你应该始终保持着警惕确保你没有挂起(持有却不用)一个MediaPlayer对象。当你处理这种情况时,你应该调用release()方法来确保系统分配给他的资源被回收。例如,如果你正在使用一个MediaPlayer,同时你的Activity收到了一个onStop()的调用,此时你必须释放MediaPlayer,因为当你的Activity并没有和用户交互的时候,你持有这个MediaPlayer是没有多大意义的(除非你在后台使用这个MediaPlayer,后面的文章会介绍在Service使用MediaPlayer的情况)。当然,当你Activity回来的时候,你需要再一次创建、准备这个一个MediaPlayer对象。
下面是如何释放和置空一个MediaPlayer对象的
mediaPlayer.release();
mediaPlayer = null;
作为一个例子,考虑这么一个情况:当你的Activity被stop了,如果你忘记释放一个MediaPlayer,同时当activity被再一次开始的时候,你的MediaPlayer会被再一次创建。你应该知道,当用户翻转屏幕的时候,系统通过重新开始这个activity来处理这种情况。如果用户反复多次的翻转屏幕,你的程序就很快的消耗掉了所有的系统资源。