MediaPlayer

来源:互联网 发布:带网络电视 编辑:程序博客网 时间:2024/06/05 07:39

MediaPlayer

Manifest 配置

如果你打算播放来自网络的多媒体文件的话,那么你必须添加访问网络的权限:

<uses-permission android:name="android.permission.INTERNET" />

如果你的播放器需要保持屏幕常亮的话,或者你调用了 MediaPlayer.setScreenOnPlaying() 或者 MediaPlayer.setWakeMode() 方法,那么你需要添加以下权限:

<uses-permission android:name="android.permission.WAKE_LOCK" />

使用 MediaPlayer

MediaPlay 可以播放来自以下 3 个地方的多媒体文件:

  • 本地文件。
  • 本地 URI,这类 URI 可以通过 ContentResolver 创建。
  • 网络 URL 流。

提示: 如果你播放的多媒体文件来自网络,那么该多媒体文件必须支持渐进式下载。

异步 prepare

需要注意的是,MediaPlayer 的 prepare() 方法可能会占用大量的时间,因为它可能涉及获取和解码多媒体数据。因此不是非常建议在 UI 线程中调用这个方法。

你可以自己新建一个线程来处理 prepare() 方法,也可以通过调用 MediaPlayerprepareAsync() 方法来实现异步加载,这个方法会立即返回,不会阻塞 UI 线程,当 MediaPlayer 准备完成后会调用 MediaPlayer.OnPreparedListeneronPrepare() 方法,你可以通过调用 MediaPlayersetOnPreparedListener() 注册异步 prepare 监听器。

状态管理

MediaPlayer 是具有内部状态的,当你编写代码时必须时刻注意 MediaPlayer 的内部状态。因为某些操作只有当 MediaPlayer 处于特定状态时才有效。如果你在错误的状态执行了错误的操作,那么有可能会导致系统抛出异常或者引发其他不良的行为。

建议在编码时对照 MediaPlayer 的 API 文档进行编码(进入文档后稍微往下翻你就能看的一个名为 “Valid and invalid states” 的对照表)。

状态图:

状态图

通过调用不同的方法,使 MediaPlayer 在不同的状态间切换。

例:

首先,当你创建一个新的 MediaPlayer 时,它处于 Idle 状态(空闲状态)。

此时,你应该调用 setDataSource() 方法来初始化 MediaPlayer,这将会把 MediaPlayer 切换到 Initialize 状态。

之后,你可以使用 prepare() 或者 prepareAsync() 方法来准备 MediaPlayer。当 MediaPlayer 准备完成后,将会切换到 Prepared 状态。这意味着你现在可以调用 start() 方法开始播放多媒体文件了。

当你调用 start() 方法后,MediaPlayer 就进入了 Statrted 状态。此时你可以通过调用 pause()、start()、seekTo() 方法在 Paused、Started、PlaybackCompleted 这三个状态间随意切换。

最后,你可以通过调用 stop() 方法来停止 MediaPlayer。注意!此时你无法通过调用 start() 方法来重新播放,你必须重新准备(prepareMediaPlayer 才能再次播放。

当你编写代码时,始终要牢记状态图,因为在错误的状态调用错误的方法会导致 MediaPlayer 抛出异常,或者导致其他的 BUG!!!

释放 MediaPlayer

一个 MediaPlayer 对象是会消耗系统资源的。因此,你必须时刻注意释放掉不再需要的 MediaPlayer 对象。

例如,如果你的 MediaPlayer 是在前台使用的(视频),那么你应该在 ActivityonStop() 中将它释放掉,如果再次回到前台,再新建一个,然后对状态进行恢复即可。

例:mediaPlayer.release();mediaPlayer = null;

考虑这样的情况,当屏幕的方向发送变换时,而你又没有在 onStop 中释放 MediaPlayer,这时又会创建一个新的 MediaPlayer,这就造成了资源泄露。

当然,如果你的 MediaPlayerService 中使用,那么不需要这么考虑,你只需在 ServiceonDestroy() 方法中释放 MediaPlayer 即可。

在 Service 中使用 MediaPlayer

如果你希望你的 MediaPlayer 在后台播放,即使此时你的应用并不在前台。也就是说,您希望它在用户与其他应用程序交互时继续播放。那么你必须启动一个 Service 然后在 Service 中创建和操作 MediaPlayer

你可以将一个 MediaPlayer 嵌入到一个名为 MediaBrowserServiceCompatService 中,然后在 Activity 中通过一个 MediaBrowserCompat 与它互动。

处理异步运行错误

在异步运行时,你必须适当的通报应用程序错误。在 MediaPlayer 中,你可以通过向 MediaPlayer 注册 MediaPlayer.OnErrorListener 监听器来监听 MediaPlayer 发送的错误。

例:public class MyService extends Service implements MediaPlayer.OnErrorListener {    MediaPlayer mMediaPlayer;    public void initMediaPlayer() {        // ...initialize the MediaPlayer here...        mMediaPlayer.setOnErrorListener(this);    }    @Override    public boolean onError(MediaPlayer mp, int what, int extra) {        // ... react appropriately ...        // The MediaPlayer has moved to the Error state, must be reset!    }}

注意!!!当错误发生是,MediaPlayer 会切换到 Error 状态。此时,你必须重置(reset)MediaPlayer 才能再次使用它。

使用唤醒锁

当你的应用程序在后台播放媒体文件时,设备可能在您的 Service 正在运行的时候进入休眠状态。因为 Android 系统试图在设备处于睡眠状态时节省电量。此时系统会试图关闭任何不需要的手机功能,包括 CPU、WiFi 设备等。如果此时你的应用程序正在播放音乐,那么应该防止系统休眠干扰到您的播放。

为了确保 CPU 能够正常的运行,你可以在初始化时调用 MediaPlayersetWakeMode() 方法来开启唤醒锁。一旦你这么做,MediaPlayer 只会在暂停或停止后释放唤醒锁。

例:mMediaPlayer = new MediaPlayer();// ... other initialization here ...mMediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);

提示: 你必须谨慎的使用唤醒锁,因为这会造成过多的电量消耗。

然而,上面的代码仅仅只能保证 CPU 的唤醒,如果你的 MediaPlayer 播放源来自网络,并且使用的是 WiFi,你可能需要获取 WifiLockWifiLock 必须手动获取与释放。

例:获取WifiLock:WifiLock wifiLock = ((WifiManager) getSystemService(Context.WIFI_SERVICE))    .createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock");wifiLock.acquire();释放WifiLock:wifiLock.release();

清理

你应该在不需要的时候清理 MediaPlayer。例如,如果你在 Service 中使用 MediaPlayer,那么你应该在 ServiceonDestroy() 方法中释放,并清理 MediaPlayer

例:public class MyService extends Service {   MediaPlayer mMediaPlayer;   // ...   @Override   public void onDestroy() {        if (mMediaPlayer != null) {            mMediaPlayer.release();        }   }}

你应该总是找机会释放你的 MediaPlayer。例如,如果用户长时间暂停了音乐,那么这时你应该释放掉你的 MediaPlayer,然后在需要的时候再次创建。如果用户仅仅是短暂的暂停音乐,那么这时可以不释放 MediaPlayer。

从一个 ContentResolver 检索多媒体文件

Android 系统的媒体扫描器会扫描 SD 卡中的媒体文件,并把它们添加到一个 ContentProvider 中,我们可以借助 ContentResolver 来获取这个 ContentProvider 中的多媒体文件列表。

例:ContentResolver contentResolver = getContentResolver();Uri uri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;Cursor cursor = contentResolver.query(uri, null, null, null, null);if (cursor == null) {    // query failed, handle error.} else if (!cursor.moveToFirst()) {    // no media on the device} else {    int titleColumn = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media.TITLE);    int idColumn = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media._ID);    do {       long thisId = cursor.getLong(idColumn);       String thisTitle = cursor.getString(titleColumn);       // ...process entry...    } while (cursor.moveToNext());}

然后你可以像下面这样使用 MediaPlayer 来播放这些多媒体文件:

例:long id = /* retrieve it from somewhere */;Uri contentUri = ContentUris.withAppendedId(        android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id);mMediaPlayer = new MediaPlayer();mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);mMediaPlayer.setDataSource(getApplicationContext(), contentUri);// ...prepare and start...

End

原创粉丝点击