Android开发指南之MediaPlayer

MediaPlayer

本文翻译至Android API开发指南之MediaPlayer。帮助我们了解什么是MediaPlayer及其基本用法与注意事项。
Android的多媒体框架支持各种常见的媒体类型,因此将各种音视频和图片资源融入你的app中将轻而易举。
播放的音视频来源主要有以下3大类:
1.app的资源文件(raw resources)
2.文件系统中的音视频文件
3.获取网络音视频资源
注意:播放音频数据仅仅支持标准输出设备。当前主要包括移动设备的扬声器和头戴式蓝牙耳机。并且不能在拨打电话的同时播放音频文件。


一、基础类

我们通常用到下面两个类来播放音频和视频
1.MediaPlayer
MediaPlayer提供API播放音频和视频。
2.AudioManager
AudioManager类用来管理音频资源和音频输出。


二、Manifest文件声明

使用MediaPlayer之前我们必须确保根据自己的需求声明了相应的权限。
1.Internet Permission 如果通过网络获取媒体资源,必须在Manifest文件中声明:

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

2.Wake Lock Permission 如果你的app需要保持常亮而不进入睡眠状态,或者你使用了MediaPlayer.setScreenOnWhilePlaying() 或MediaPlayer.setWakeMode()方法,则必须在Manifest文件中声明:

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

三、使用MediaPlayer

使用MediaPlayer最重要的类是MediaPlayer,通过该类能够以最少的设置来获取、解析和播放音视频。它支持3种类型的资源途径:
1.本地资源(Local resources)
2.内部URLs(例如ContentResolver
3.外部URLs(网络资源)
关于Android支持的所有媒体格式,请查看Supported Media Formats


使用示例:
1.获取App内部res/raw/directory中的资源

MediaPlayer mediaPlayer = MediaPlayer.create(context, R.raw.sound_file_1);
mediaPlayer.start(); //不需要调用prepare(),因为create()方法已经帮你实现了。

值得注意的是,上例中的raw资源系统不会以特定方式进行解析。因此,该raw资源不能是原始音频,必须为已经被正确解析过后的Android所支持的媒体格式。


2.通过内部URL(例如ContentResolver)获取资源

Uri myUri = ....; // 初始化Uri
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(getApplicationContext(), myUri);
mediaPlayer.prepare();
mediaPlayer.start();

3.通过HTTP获取资源

String url = "http://........"; // url地址
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(url);
mediaPlayer.prepare(); // 可能会很耗时! (例如buffering, etc)
mediaPlayer.start();

注意:如果你传入的url是一个网络媒体文件,那么该文件必能进行渐进式下载
当你调用setDataSource()方法时,因为你引用的文件可能不存在,必须处理IllegalArgumentException 和IOException异常。


四、Asynchronous preparation(异步preparation)

在使用MediaPlayer时有几件事必须注意。例如在prepare()方法中进行media数据的获取和解析可能会很耗时,只要是耗时的方法,都不要在UI线程中执行,因为这很可能会导致ANR。
为了避免在UI线程中执行耗时任务,MediaPlayer提供了prepareAsync()方法。该方法在后台准备media数据并且立即返回。当media数据准备完毕后,回调MediaPlayer.OnPreparedListener的onPrepared()方法,通过 setOnPreparedListener()方法进行事件注册。

五、状态管理(Managing state)

另外一件需要注意的事情就是MediaPlayer是基于状态的。意思是当你编写代码的时候必须随时意识到MediaPlayer存在一种内部状态(internal state),因为只有当播放器在某些特定状态时一些操作才是合法的。在错误的状态执行了错误的操作,后果自负(:P)。


MediaPlayer类中的状态图说明了哪些方法将MediaPlayer从一个状态转为另一个状态。
这里写图片描述
例如,当create一个新的MediaPlayer时,进入Idle状态。在这个状态你应该调用setDataSource()方法进行初始化,将它转变为Initialized状态。具体方法和状态转换如上图所示。所以我们在调用MediaPlayer相关的方法时,一定要在正确的状态中调用,否则就可能出错。

六、释放MediaPlayer资源

mediaPlayer.release();
mediaPlayer = null;

将MediaPlayer与所在Activity或Service的生命周期进行绑定,当Activity或Service销毁时一定要在onDestroy()方法中释放MediaPlayer资源。

七、在Service中使用MediaPlayer实例

如果你想在后台播放媒体,即使你的应用程序已经不可见了,那么我们就该启动一个Service来控制MediaPlayer。可以了解下 MediaBrowserServiceCompat和 MediaBrowserCompat(Building an Audio App)。

1.异步运行(Running asynchronously)

public class MyService extends Service implements MediaPlayer.OnPreparedListener {
    private static final String ACTION_PLAY = "com.example.action.PLAY";
    MediaPlayer mMediaPlayer = null;

    public int onStartCommand(Intent intent, int flags, int startId) {
        ...
        if (intent.getAction().equals(ACTION_PLAY)) {
            mMediaPlayer = ... // initialize it here
            mMediaPlayer.setOnPreparedListener(this);
            mMediaPlayer.prepareAsync(); // prepare async to not block main thread
        }
    }

    /** Called when MediaPlayer is ready */
    public void onPrepared(MediaPlayer player) {
        player.start();
    }
}

2.处理异步错误

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!
    }
}

3.使用wake locks(唤醒锁)
当手机进入睡眠状态的时候,如果想让你的应用保持运行,就得用到wake locks。
注意:该用的时候用,不该用的时候别用,因为损耗电池。


初始化的时候调用setWakeMode()方法。 MediaPlayer会在媒体播放时保持这个锁,在pause或stop的时候release。

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

当你使用wifi访问网络资源的时候,你还需要create和acquire一个wi-fi lock:

WifiLock wifiLock = ((WifiManager) getSystemService(Context.WIFI_SERVICE))
    .createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock");

wifiLock.acquire();

当pause或stop你的MediaPlayer,或者断网了,需要释放wi-fi lock:

wifiLock.release();

4.回收资源

public class MyService extends Service {
   MediaPlayer mMediaPlayer;
   // ...

   @Override
   public void onDestroy() {
       if (mMediaPlayer != null) mMediaPlayer.release();
   }
}

当然你也可以自己控制在什么地方释放资源,但是切记一定要在不需要的时候释放。


5.通过ContentResolver获取media资源

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());
}

得到了id后就可以播放啦:

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...

本文简要的介绍了MediaPlayer的使用方法与注意事项,具体在项目中的应用将在后续进行说明。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值