由于许多App都可能会播放多媒体文件,对于它们之间该如何相互作用就必须要充分考虑。为了避免所有的音乐App同时播放音乐,Android系统提供了audio焦点机制来控制多媒体文件的播放,只有获得了audio焦点的App能够播放音乐。
在你的App播放音频文件之前,需要请求并接受audio焦点。同样的,需要明白如何监听audio焦点的丢失并且在其发生时妥善处理。
Android系统Audio焦点的常用的操作方法如下:
Request the Audio Focus
在你的App开始播放音乐之前,它应该持有一个它将会使用到的audio stream的audio焦点。获取焦点的操作由调用 requestAudioFocus()方法,并且在你请求成功的时候会返回 AUDIOFOCUS_REQUEST_GRANTED。
无论你想暂时或是永久地申请audio焦点,你应该指定哪一个audio stream你将会使用。在你期望播放一段短时间的音频的时候申请一个瞬间的audio焦点(例如播放导航指示音),在你播放长时音频的时候申请永久的audio焦点(例如播放音乐)。
下面的代码片段展示了在使用音乐audio stream时如何获取永久的audio焦点。你应该在你播放音频之前就申请audio焦点,例如在用户按下播放按钮或者是在进入下一个游戏难度时播放背景音乐之前就申请audio焦点。
1 AudioManager am = mContext.getSystemService(Context.AUDIO_SERVICE); 2 ... 3 4 // Request audio focus for playback 5 int result = am.requestAudioFocus(afChangeListener, 6 // Use the music stream. 7 AudioManager.STREAM_MUSIC, 8 // Request permanent focus. 9 AudioManager.AUDIOFOCUS_GAIN); 10 11 if(result ==AudioManager.AUDIOFOCUS_REQUEST_GRANTED){ 12 am.registerMediaButtonEventReceiver(RemoteControlReceiver); 13 // Start playback. 14 }
一旦你播放完音乐,一定要记住调用 abandonAudioFocus()方法,该方法会通知系统你不再需要audio焦点并且注销之前关联的 AudioManager.OnAudioFocusChangeListener监听器。在短暂地放弃焦点的情况下,android系统允许被打断的App继续播放音乐。
1 // Abandon audio focus when playback complete 2 am.abandonAudioFocus(afChangeListener);
在注册临时的audio焦点的时候你还有一个可选的操作方法:你是否想使用“ducking”机制。通常的,当一个正在播放音乐的app丢失audio焦点的时候,它就会立刻停止播放。通过使用“ducking”的方法来请求一个临时的焦点则可以避免上述情况,该机制允许正在播放音乐的App调低音量接着播放,直到audio焦点返还给它们,音量重新恢复。
1 // Request audio focus for playback 2 int result = am.requestAudioFocus(afChangeListener, 3 // Use the music stream. 4 AudioManager.STREAM_MUSIC, 5 // Request permanent focus. 6 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK); 7 8 if(result ==AudioManager.AUDIOFOCUS_REQUEST_GRANTED){ 9 // Start playback. 10 }
“ducking”机制特别适合于仅需要短暂地获取audio焦点的场景,利用在利用导航软件听取导航指示时。
其他的App无论何时如上述的方法请求audio焦点,是想获取永久的audio焦点或者是临时的audio焦点(不管是否支持“ducking”机制),它们都是通过它们注册的监听器来获取audio焦点的。
处理Audio焦点的丢失问题
如果你的App能够请求audio焦点,那么在众多的app都在请求audio焦点的时候它们会轮流地丢失焦点。你的App在丢失audio焦点的时候如何反应是根据丢失焦点的方式决定的。
你注册的audio焦点监听器通常会有一个 onAudioFocusChange()回调函数,它会携带一个描述audio焦点变化事件的变量。特别的,可能发生的audio焦点丢失事件与之前的焦点请求类型是对应的,有永久丢失,临时丢失以及允许“ducking”机制的临时丢失。
一般来说,一个临时的audio焦点丢失事件,通常会导致你的app使它使用的audio stream静音,但是从另一方面来说需要保存它的状态。你的App应该持续监听audio焦点的变化,随时准备着在重新获取到焦点的时候播放之前的音乐。
如果audio焦点丢失是永久的,应用程序已经被用户播放音乐了,那么你的app应该做出有效的响应。在实际操作中,通常是你的app需要停止播放,移除多媒体按钮事件的监听,允许正在播放音乐的播放器专一地处理那些事件,同时取消掉你自己的audio焦点。在这个时候,你应该设计出一种用户的操作(例如在你的app中点击播放),通过该操作来重新恢复你的音乐播放。
下面的代码片段展示出了在临时丢失audio焦点时,我们暂停我们的音乐播放,在重新获取audio焦点时,我们恢复播放。如果audio焦点是永久地丢失,则注销我们的多媒体按钮事件监听器,并且停止对audio焦点变化的监听。
1 AudioManager.OnAudioFocusChangeListener afChangeListener = 2 newAudioManager.OnAudioFocusChangeListener(){ 3 publicvoid onAudioFocusChange(int focusChange){ 4 if(focusChange == AUDIOFOCUS_LOSS_TRANSIENT){ 5 // Pause playback 6 }elseif(focusChange ==AudioManager.AUDIOFOCUS_GAIN){ 7 // Resume playback 8 }elseif(focusChange ==AudioManager.AUDIOFOCUS_LOSS){ 9 am.unregisterMediaButtonEventReceiver(RemoteControlReceiver); 10 am.abandonAudioFocus(afChangeListener); 11 // Stop playback 12 } 13 } 14 };
在临时丢失audio焦点的时候可能会遇到“ducking”机制允许的情况,这样你就不用暂停你的播放,你可以采用“duck”方法。
Duck!
“ducking”机制是在其他的app申请audio焦点的时候降低你的app使用的audio steam的音量,从而避免直接屏蔽掉你的app的一种机制。
下面的代码片段展示了在临时丢失audio焦点的时候调低你的app的音量,并且在重新获取到audio焦点的时候将音量恢复到之前的大小。
1 OnAudioFocusChangeListener afChangeListener =newOnAudioFocusChangeListener(){ 2 publicvoid onAudioFocusChange(int focusChange){ 3 if(focusChange == AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK){ 4 // Lower the volume 5 }elseif(focusChange ==AudioManager.AUDIOFOCUS_GAIN){ 6 // Raise it back to normal 7 } 8 } 9 };
audio焦点的丢失是最重要的需要作出反应的广播事件,但是并不是唯一的。系统会广播许多的intents来提醒你对于你的app作出调整,一遍提高用户的体验。下一节会展示出你怎么合理应对上述的广播事件能够提高用户的体验。