Android MediaPlayer

MediaPlayer react

这个类主要是播放视频类. android

AudioManager api

这个类管理在一个设备上的音频资源和音频输出流. 网络


Manifest声明 app

1.网络声明 框架

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

2.若是播放器应用须要将屏幕变暗或者中止处理器,或者须要调用 MediaPlayer.setScreenOnWhilePlaying() 或者 MediaPlayer.setWakeMode()  方法,须要声明: async

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


MediaPlayer类的使用 post

MediaPlayer类支持几种不一样媒体来源例如:

1. 本地资源

2. 网络URI

3. 外部URL()


媒体来源1: 本地资源(存储在应该的res/raw/ 目录下)

MediaPlayer mediaPlayer = MediaPlayer.create(context, R.raw.sound_file_1);
mediaPlayer.start(); // no need to call prepare(); create() does that for you

这种状况下,一个"raw"资源是不须要系统作任何解析的一个文件.然而,这个资源不该该是原始音频文件.它应该是一个被支持的正确编码和格式化的媒体文件.


媒体来源2: 网络URI

Uri myUri = ....; // initialize Uri here
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(getApplicationContext(), myUri);
mediaPlayer.prepare();
mediaPlayer.start();


媒体来源3: 经过HTTP取得的远程URL

String url = "http://........"; // your URL here
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(url);
mediaPlayer.prepare(); // might take long! (for buffering, etc)
mediaPlayer.start();

注意:在调用setDataSource(), 方法的时候必定要catch 得到 抛出  IllegalArgumentException  IOException 两个异常,由于你定义的文件可能不存在.  


Asynchronous Preparation 异步准备

原则上能够直接使用MediaPlayer.可是,有一些事情必需要一体化例如,调用prepare()  方法可能花费很长时间来执行,由于它可能涉及到抓取或者编码媒体数据.所以,这中状况下任何方法都有可能花费很长时间去执行,你不该该在UI线程中调用这个方法.

框架支持的一个很方便完成这个操做的方法是:调用 prepareAsync() 方法.这个方法在后台开始prepare媒体而且立刻就返回.media准备完成.经过设置 setOnPreparedListener()  的 MediaPlayer.OnPreparedListener 接口中 onPrepared() 方法就会被调用.


Managing State(状态管理)

 MediaPlayer 有一个内部状态当你写你的代码时你必须时刻注意,由于某些操做只有在特定的状态下才有效.

具体状态请查看SDK文档中 MediaPlayer 类.


Releasing the MediaPlayer(释放MediaPlayer)

一个MediaPlayer 可能会消耗大量的系统资源.所以,你应该老是采起额外的方式去确保你不会持有一个MediaPlayer 实例,超过实际须要.

当你完成操做时时,你应该老是调用 release() 方法去确保任何分配的系统资源给正确的释放掉.例如,当你使用一个MediaPlayer 而你的activity调用onStop()方法时,你必定要释放MediaPlayer .由于当你的activity没有和用户交互的时候,去持有一个MediaPlayer意义不大.(除非须要在后台播放媒体文件).

当你的activityresumed  或者 restarted 状态,你须要去建立一个新的MediaPlayer  而且准备再次回复以前的播放.

这里是释放和让MediaPlayer 为null的代码:

mediaPlayer.release();
mediaPlayer = null;


Using a Service with MediaPlayer

Running asynchronously(异步运行)

首先,像一个activity同样,在一个Service中的全部工做默认的是在一个单独的线程中,若是你在同一个应用中运行一个activity和一个Service,默认的他们使用的是同一个线程(主线程).所以,service须要快速处理引入的intent而且在处理这些intent的时候不要处理冗长的运算.

若是须要这么作,你必定要异步处理这些事情.

举例来讲,当在你的主线程中使用一个 MediaPlayer 时.你应该调用 prepareAsync()  而不是 prepare() ,例如:

public class MyService extends Service implements MediaPlayer.OnPreparedListener {
    private static final 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();
    }
}



Handling asynchronous errors(异常异步处理)

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状态而且在你再次使用它以前你必定要重置 MediaPlayer.



Using wake locks

当设计应用在后台播放媒体文件时,设备在你的service运行的时候可能会待机由于android系统在设备待机的时候尝试节省电池.全部系统会尝试切断任何非必要的手机特征,包括CPUWifi硬件.然而,若是你的service正在播放或者流处理音乐,你会想防止系统干扰你的播放.

为了确保你的service继续运行在这些条件下,你须要使用"wake locks".一个wake lock 是一种提醒体统你的应用正在使用一些特性,系统应该保持可用,就算电话处于空闲状态.

注意:你应该老是节俭的使用wake locks,而且持有他们只有在真正必要的时候,由于他们会大大下降设备电池寿命.

要确保CPU在你的 MediaPlayer  播放的时候继续处于运行状态,当初始化你的 MediaPlayer 时调用 setWakeMode()  . 一旦你这么作了, MediaPlayer 会持有指定的lock在播放的时候而且在paused或者stoped状态时,会释放掉这个lock.

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

在这个例子中得到wake lock 的前提是只有当CPU处于清醒状态.若是你是经过网络流媒体而且使用的是wifi的话,你能够也想要去持有一个 WifiLock  ,这种方式你必须收到获取和释放.所以,当你开始经过远程URL准备 MediaPlayer  时,你应该建立和得到 Wi-Fi lock .例如:

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

wifiLock.acquire();

当你暂停或者中止媒体,或者你很长时间没有用到网络,你应该释放这个lock:

wifiLock.release();



Handling audio focus(处理音频的焦点)

尽管只有一个activity能够运行在任什么时候候,可是android 是一个多任务环境.这给使用音频的应用产生了一个特别的挑战,由于哪里只有一个音频输入可是可能有几个媒体service竞争使用.android2.2以前,没有一个内置机制来解决这个问题.这可能在某些状况下致使糟糕的用户体验.

当你的应用须要输入音频时,你应该老是请求音频聚焦(audio focus).一旦它有了,它可使用自由的输出声音了,可是它应该老是保持对焦点的监听.若是它被通知它已经失去了音频焦点,它应该立刻杀掉这个音频或者下降它到一个安静的水平而且只有当它再次接受到focus时再从新播放.

要请求音频聚焦,你必定要调用 AudioManager 的 requestAudioFocus() 方法,

AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC,
    AudioManager.AUDIOFOCUS_GAIN);

if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
    // could not get audio focus.
}

 requestAudioFocus() 方法的第一个参数是一个 AudioManager.OnAudioFocusChangeListener ,当一个音频焦点发生改变的时候他的 onAudioFocusChange() 方法会被调用.

所以你能够在activity或者service中实现这个接口:

class MyService extends Service
                implements AudioManager.OnAudioFocusChangeListener {
    // ....
    public void onAudioFocusChange(int focusChange) {
        // Do something based on focus change...
    }
}

focusChange  参数告诉你音频焦点发生了什么样的改变:

· AUDIOFOCUS_GAIN你获得这个音频的焦点

· AUDIOFOCUS_LOSS你可能长时间失去了这个音频的焦点你必定要中止全部的音频播放.由于你应该但愿不要在后台聚焦太长事件,这个是一个好地方去尽量的释放掉你的资源.例如:你应该释放掉MediaPlayer.

· AUDIOFOCUS_LOSS_TRANSIENT你暂时的失去了音频的焦点,可是应该要立刻回到焦点上.你必定要中止掉全部的音频的播放,可是你能持有你的资源由于你可能很快的再次得到聚焦.

· AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK你暂时的失去了音频的焦点,可是你容许继续用小音量播放音乐而不是彻底杀掉音频.

使用代码:

public void onAudioFocusChange(int focusChange) {
    switch (focusChange) {
        case AudioManager.AUDIOFOCUS_GAIN:
            // resume playback
            if (mMediaPlayer == null) initMediaPlayer();
            else if (!mMediaPlayer.isPlaying()) mMediaPlayer.start();
            mMediaPlayer.setVolume(1.0f, 1.0f);
            break;

        case AudioManager.AUDIOFOCUS_LOSS:
            // Lost focus for an unbounded amount of time: stop playback and release media player
            if (mMediaPlayer.isPlaying()) mMediaPlayer.stop();
            mMediaPlayer.release();
            mMediaPlayer = null;
            break;

        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
            // Lost focus for a short time, but we have to stop
            // playback. We don't release the media player because playback
            // is likely to resume
            if (mMediaPlayer.isPlaying()) mMediaPlayer.pause();
            break;

        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
            // Lost focus for a short time, but it's ok to keep playing
            // at an attenuated level
            if (mMediaPlayer.isPlaying()) mMediaPlayer.setVolume(0.1f, 0.1f);
            break;
    }
}

记住这些api只有在API 等级为8(android 2.2)或者之上才能用.

Handling the AUDIO_BECOMING_NOISY Intent 

有可能会出现噪音的状况,例如,用户先用耳机听音乐,而后把耳机给拔出来的这种状况.

你能够经过处理 ACTION_AUDIO_BECOMING_NOISY 意图来确保在这种状况下,你的应用中止播放音乐.

<receiver android:name=".MusicIntentReceiver">
   <intent-filter>
      <action android:name="android.media.AUDIO_BECOMING_NOISY" />
   </intent-filter>
</receiver>

public class MusicIntentReceiver implements android.content.BroadcastReceiver {
   @Override
   public void onReceive(Context ctx, Intent intent) {
      if (intent.getAction().equals(
                    android.media.AudioManager.ACTION_AUDIO_BECOMING_NOISY)) {
          // signal your service to stop playback
          // (via an Intent, for instance)
      }
   }
}



文章连接:http://blog.csdn.net/murongshusheng/article/details/7580689

相关文章
相关标签/搜索