管理音频播放(摘自Android官方培训课程中文版(v0.9.5))
如果我们的应用能够播放音频,那么让用户能够以自己预期的方式控制音频是很重要的。为了保证良好的用户体验,我们应该让应用能够管理当前的音频焦点,因为这样才能确保多个应用不会在同一时刻一起播放音频。
在学习本系列课程中,我们将会创建可以对音量按钮进行响应的应用,该应用会在播放音频的时候请求获取音频焦点,并且在当前音频焦点被系统或其他应用所改变的时候,做出正确的响应。
Lessons
控制音量与音频播放(Controlling Your App’s Volume and Playback)
学习如何确保用户能通过硬件或软件音量控制器调节应用的音量(通常这些控制器上还具有播放、停止、暂停、跳过以及回放等功能按键)。
管理音频焦点(Managing Audio Focus)
由于可能会有多个应用具有播放音频的功能,考虑他们如何交互非常重要。为了防止多个音乐应用同时播放音频,Android使用音频焦点(Audio Focus)来控制音频的播放。在这节课中可以学习如何请求音频焦点,监听音频焦点的丢失,以及在这种情况发生时应该如何做出响应。
兼容音频输出设备(Dealing with Audio Output Hardware)
音频有多种输出设备,在这节课中可以学习如何找出播放音频的设备,以及处理播放时耳机被拔出的情况。
控制音量与音频播放
编写:kesenhoo- 原文:http://developer.android.com/training/managing-audio/volume-playback.html
良好的用户体验应该是可预期且可控的。如果我们的应用可以播放音频,那么显然我们需要做到能够通过硬件按钮,软件按钮,蓝牙耳麦等来控制音量。 同样地,我们需要能够对应用的音频流进行播放(Play),停止(Stop),暂停(Pause),跳过(Skip),以及回放(Previous)等动作,并且并确保其正确性。
鉴别使用的是哪个音频流(Identify Which Audio Stream to Use)
为了创建一个良好的音频体验,我们首先需要知道应用会使用到哪些音频流。Android为播放音乐,闹铃,通知铃,来电声音,系统声音,打电话声音与拨号声音分别维护了一个独立的音频流。这样做的主要目的是让用户能够单独地控制不同的种类的音频。上述音频种类中,大多数都是被系统限制。例如,除非你的应用需要做替换闹钟的铃声的操作,不然的话你只能通过STREAM_MUSIC来播放你的音频。
使用硬件音量键来控制应用的音量(Use Hardware Volume Keys to Control Your App’s Audio Volume)
默认情况下,按下音量控制键会调节当前被激活的音频流,如果我们的应用当前没有播放任何声音,那么按下音量键会调节响铃的音量。对于游戏或者音乐播放器而言,即使是在歌曲之间无声音的状态,或是当前游戏处于无声的状态,用户按下音量键的操作通常都意味着他们希望调节游戏或者音乐的音量。你可能希望通过监听音量键被按下的事件,来调节音频流的音量。其实我们不必这样做。Android提供了setVolumeControlStream()方法来直接控制指定的音频流。在鉴别出应用会使用哪个音频流之后,我们需要在应用生命周期的早期阶段调用该方法,因为该方法只需要在Activity整个生命周期中调用一次,通常,我们可以在负责控制多媒体的Activity或者Fragment的onCreate()
方法中调用它。这样能确保不管应用当前是否可见,音频控制的功能都能符合用户的预期。
setVolumeControlStream(AudioManager.STREAM_MUSIC);
自此之后,不管目标Activity或Fragment是否可见,按下设备的音量键都能够影响我们指定的音频流(在这个例子中,音频流是"music")。
使用硬件的播放控制按键来控制应用的音频播放(Use Hardware Playback Control Keys to Control Your App’s Audio Playback)
许多线控或者无线耳机都会有许多媒体播放控制按钮,例如:播放,停止,暂停,跳过,以及回放等。无论用户按下设备上任意一个控制按钮,系统都会广播一个带有ACTION_MEDIA_BUTTON的Intent。为了正确地响应这些操作,需要在Manifest文件中注册一个针对于该Action的BroadcastReceiver,如下所示:
在Receiver的实现中,需要判断这个广播来自于哪一个按钮,Intent通过EXTRA_KEY_EVENT这一Key包含了该信息,另外,KeyEvent类包含了一系列诸如KEYCODE_MEDIA_*
的静态变量来表示不同的媒体按钮,例如KEYCODE_MEDIA_PLAY_PAUSE与KEYCODE_MEDIA_NEXT。
public class RemoteControlReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) {
KeyEvent event = (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
if (KeyEvent.KEYCODE_MEDIA_PLAY == event.getKeyCode()) {
// Handle key press.
}
}
}
}
因为可能会有多个程序在监听与媒体按钮相关的事件,所以我们必须在代码中控制应用接收相关事件的时机。下面的例子显示了如何使用AudioManager来为我们的应用注册监听与取消监听媒体按钮事件,当Receiver被注册上时,它将是唯一一个能够响应媒体按钮广播的Receiver。
AudioManager am = mContext.getSystemService(Context.AUDIO_SERVICE);
...
// Start listening for button presses
am.registerMediaButtonEventReceiver(RemoteControlReceiver);
...
// Stop listening for button presses
am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
通常,应用需要在他们失去焦点或者不可见的时候(比如在onStop()方法里面)取消注册监听。但是对于媒体播放应用来说并没有那么简单,实际上,在应用不可见(不能通过可见的UI控件进行控制)的时候,仍然能够响应媒体播放按钮事件是极其重要的。为了实现这一点,有一个更好的方法,我们可以在程序获取与失去音频焦点的时候注册与取消对音频按钮事件的监听。这个内容会在后面的课程中详细讲解。
管理音频焦点
编写:kesenhoo- 原文:http://developer.android.com/training/managing-audio/audio-focus.html
由于可能会有多个应用可以播放音频,所以我们应当考虑一下他们应该如何交互。为了防止多个音乐播放应用同时播放音频,Android使用音频焦点(Audio Focus)来控制音频的播放——即只有获取到音频焦点的应用才能够播放音频。
在我们的应用开始播放音频之前,它需要先请求音频焦点,然后再获取到音频焦点。另外,它还需要知道如何监听失去音频焦点的事件并对此做出合适的响应。
请求获取音频焦点(Request the Audio Focus)
在我们的应用开始播放音频之前,它需要获取将要使用的音频流的音频焦点。通过使用requestAudioFocus()方法可以获取我们希望得到的音频流焦点。如果请求成功,该方法会返回AUDIOFOCUS_REQUEST_GRANTED。
另外我们必须指定正在使用的音频流,而且需要确定所请求的音频焦点是短暂的(Transient)还是永久的(Permanent)。
短暂的焦点锁定:当计划播放一个短暂的音频时使用(比如播放导航指示)。 永久的焦点锁定:当计划播放一个较长但时长可预期的音频时使用(比如播放音乐)。下面的代码片段是一个在播放音乐时请求永久音频焦点的例子,我们必须在开始播放之前立即请求音频焦点,比如在用户点击播放或者游戏中下一关的背景音乐开始前。
AudioManager am = mContext.getSystemService(Context.AUDIO_SERVICE);
...
// Request audio focus for playback
int result = am.requestAudioFocus(afChangeListener,
// Use the music stream.
AudioManager.STREAM_MUSIC,
// Request permanent focus.
AudioManager.AUDIOFOCUS_GAIN);
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
am.registerMediaButtonEventReceiver(RemoteControlReceiver);
// Start playback.
}
一旦结束了播放,需要确保调用了abandonAudioFocus()方法。这样相当于告知系统我们不再需要获取焦点并且注销所关联的AudioManager.OnAudioFocusChangeListener监听器。对于另一种释放短暂音频焦点的情况,这会允许任何被我们打断的应用可以继续播放。
// Abandon audio focus when playback complete
am.abandonAudioFocus(afChangeListener);
当请求短暂音频焦点的时候,我们可以选择是否开启“Ducking”。通常情况下,一个应用在失去音频焦点时会立即关闭它的播放声音。如果我们选择在请求短暂音频焦点的时候开启了Ducking,那意味着其它应用可以继续