共计 4591 个字符,预计需要花费 12 分钟才能阅读完成。
音频焦点治理的意义
两个或两个以上的 Android 利用可同时向同一输入流播放音频。零碎会将所有音频流混合在一起。尽管这是一项杰出的技术,但却会给用户带来很大的困扰。为了防止所有音乐利用同时播放,Android 引入了“音频焦点”的概念。一次只能有一个利用取得音频焦点。
当您的利用须要输入音频时,它须要申请取得音频焦点,取得焦点后,就能够播放声音了。不过,在您取得音频焦点后,您可能无奈将其始终持有到播放实现。其余利用能够申请焦点,从而占有您持有的音频焦点。如果产生这种状况,您的利用应暂停播放或升高音量,以便于用户听到新的音频源。
音频焦点治理的行为准则
- 在行将开始播放之前调用
requestAudioFocus()
,并验证调用是否返回AUDIOFOCUS_REQUEST_GRANTED
。 - 在其余利用取得音频焦点时,应该进行或者暂停播放,或者升高音量。
- 播放进行后应该放弃音频焦点
版本兼容
从 Android 8.0(O 版本,API 26)开始,音频焦点的申请形式以及系统管理有了轻微的变动,上面分两局部来阐明。
在 Android 8.0(API 26) 之前对音频焦点具体解决实现
当想录音或者播放歌曲的时候,最好 (非必须) 先申请音频焦点,这个时候须要调用 AudioManager.requestAudioFocus()办法,函数原型如下
AudioManager.requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint)
第一个参数用于监听焦点变动
第二个参数表明申请的音频焦点影响的是那种类型流,例如,如果咱们录音,咱们必定是要影响 Music 这一类型的音频流,因而能够抉择AudioManager.STREAM_MUSIC
。当然还有许多类型。
/** 通话相干 */
public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
/** 零碎声音 */
public static final int STREAM_SYSTEM = AudioSystem.STREAM_SYSTEM;
/** 铃声 */
public static final int STREAM_RING = AudioSystem.STREAM_RING;
/** 音乐相干 */
public static final int STREAM_MUSIC = AudioSystem.STREAM_MUSIC;
/** 闹钟相干 */
public static final int STREAM_ALARM = AudioSystem.STREAM_ALARM;
第三个参数用于表明音频焦点的持续时间,这个很要害,它也有许多种类型,上面一一列出。
AudioManager.AUDIOFOCUS_GAIN
: API 文档说申请的这类音频焦点持续时间是未知的,通常用来示意长时间获取焦点,能够用来播放音乐,录音等等。AudioManager.AUDIOFOCUS_GAIN_TRANSIENT
: 表明申请的音频焦点持续时间比拟短,通常用来播放导航路线的声音,或者播放告诉声音。AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
: 这个也是表明申请的音频焦点持续时间比拟短,然而在这段时间内,它心愿其余利用以较低音量持续播放。例如,咱们在应用导航的时候能够听音乐,当呈现导航语音的时候,音乐音量会升高以便咱们能听分明导航的语音,当导航语音播放结束后,音乐复原音量,持续播放。AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE
: 这个也是表明音申请的音频焦点持续时间比拟短,然而在这段时间内,不心愿任何利用 (包含零碎利用) 来做任何与音频相干的事件,就算是升高音量播放音乐也是不被心愿的。例如当咱们进行录音或者语音辨认的时候,咱们不心愿其余的声音呈现烦扰。
AudioManager.requestAudioFocus()
的返回值表明申请的后果 AudioManager.AUDIOFOCUS_REQUEST_FAILED
表明申请焦点失败,AudioManager.AUDIOFOCUS_REQUEST_GRANTED
表明申请焦点胜利。
当咱们胜利申请焦点后,就能够做一些与音频无关的事件,例如播放音乐,录音,或者语音辨认。当实现这些工作后,咱们必须调用 AudioManager.abandonAudioFocus(onAudioFocusChangeListener l)
开释音频焦点。
8.0 之后实现
从 Android 8.0 开始(API 26),申请音频焦点的形式以及系统对音频焦点变动的治理有些奥妙的变动。首先,对音频焦点变动的治理的变动体现在两个方面,提早获取焦点和主动升高音量。
提早获取焦点
在 Android 8.0 之前,当咱们申请音频焦点的时候,只会返回两种后果,要么申请胜利(AUDIOFOCUS_REQUEST_GRANTED
),要么申请失败(AUDIOFOCUS_REQUEST_FAILED
)。
而从 Android 8.0 开始,还有一种后果,提早胜利申请(AUDIOFOCUS_REQUEST_DELAYED
),这个也是胜利的申请,然而这个申请具备提早性。例如当咱们处于通话状态的时候,咱们很显然不心愿任何 app 来获取到音频焦点来做些事,例如播放音乐。
然而只有设置过 AudioFocusRequest.Builder.setAcceptsDelayedFocusGain(true)
能力获取到这种后果,这个咱们前面会讲到。那么咱们怎么晓得什么时候获取到了音频焦点呢,当然还须要设置 AudioManager.OnAudioFocusChangeListener
这个音频焦点变动的监听器,通过回调确认何时获取到了音频焦点。
主动升高音量
在 Android 8.0 之前,如果申请焦点应用了 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
参数,它表明心愿领有了音频焦点的其余利用升高音量来应用音频,然而并不是所有的利用都会这样做(有可能开发者遗记了优化),因为这并不是零碎强制的。But, 从 Android 8.0 开始,这个升高音量的工作,就是零碎默认行为了,能够说是一个良心的优化。
如果我不心愿零碎主动给我升高音量,而是想本人暂停音频相干的工作,那咋办?这个能够通过 AudioFocusRequest.Builder.setWillPauseWhenDucked(true)
办法勾销零碎的默认行为,而后通过监听音频焦点变动
音频焦点申请形式
从 Android 8.0(API 级别 26)开始,当您调用 requestAudioFocus()
时,必须提供 AudioFocusRequest
参数。要开释音频焦点,请调用 abandonAudioFocusRequest()
办法,该办法也承受 AudioFocusRequest
作为参数。在申请和放弃焦点时,应应用雷同的 AudioFocusRequest
实例
要创立 AudioFocusRequest
,请应用 AudioFocusRequest.Builder
。因为焦点申请始终必须指定申请的类型,因而此类型会蕴含在构建器的构造函数中。应用构建器的办法来设置申请的其余字段
setFocusGain()
: 只有这个办法是必须的,而传入的参数与 8.0 之前应用AudioManager.requestAudioFocus()
传入的第三个参数一样,都是用来示意持续时间。setAudioAttributes()
: 这个办法是用来形容 app 的应用状况。这办法须要传入一个 AudioAttributes 对象,这个对象也是应用 Builder 模式来结构,例如应用AudioAttributes.Builder.setUsage()
来形容应用这个音频来干什么,咱们能够传入一个AudioAttributes.USAGE_MEDIA
来表明用这个音频来作为媒体文件来播放,也能够传入一个AudioAttributes.USAGE_ALARM
来表明用这个来作为闹铃。setWillPauseWhenDucked()
: 这个后面说过,是为了笼罩零碎默认升高音量的行为,然而必须要设置AudioManager.OnAudioFocusChangeListener
能力本人解决这类状况。setAcceptsDelayedFocusGain()
: 这个后面也说过,这个是为了可能提早获取到焦点的必须条件,然而同时也必须要设置AudioManager.OnAudioFocusChangeListener
能力得悉何时获取到焦点。setOnAudioFocusChangeListener()
: 音频焦点变动监听器。值得一提的是这个办法有个重载的办法,有一个重载办法有两个参数,第二个参数为 Handler 对象,看到 Handler 应该明确了,是为了应用它的音讯队列来程序解决这个回调
响应音频焦点更改
当利用取得音频焦点后,它必须可能在其余利用为本人申请音频焦点时开释该焦点。呈现这种状况时,您的利用会收到对 AudioFocusChangeListener
中的 onAudioFocusChange()
办法的调用,该办法是您在利用调用 requestAudioFocus()
时指定的。
传递给 onAudioFocusChange()
的 focusChange
参数示意所产生的更改类型。它对应于获取焦点的利用所应用的持续时间提醒。您的利用应该做出适当的响应
暂时性失去焦点
如果焦点更改是暂时性的(AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
或 AUDIOFOCUS_LOSS_TRANSIENT
),您的利用应该升高音量(如果您不依赖于[主动升高音量])或暂停播放,否则放弃雷同的状态。
在暂时性失去音频焦点时,您应该持续监控音频焦点的变动,并筹备好在从新取得焦点后恢复正常播放。当抢占焦点的利用放弃焦点时,您会收到一个回调 (AUDIOFOCUS_GAIN
)。此时,您能够将音量复原到失常程度或从新开始播放。
永久性失去焦点
如果是永久性失去音频焦点 (AUDIOFOCUS_LOSS
),则其余利用会播放音频。您的利用应立即暂停播放,因为它不会收到 AUDIOFOCUS_GAIN
回调。要从新开始播放,用户必须执行明确的操作,例如在告诉或利用界面中按播放传输控件。
相干教程
Android 根底系列教程:
Android 根底课程 U - 小结_哔哩哔哩_bilibili
Android 根底课程 UI- 布局_哔哩哔哩_bilibili
Android 根底课程 UI- 控件_哔哩哔哩_bilibili
Android 根底课程 UI- 动画_哔哩哔哩_bilibili
Android 根底课程 -activity 的应用_哔哩哔哩_bilibili
Android 根底课程 -Fragment 应用办法_哔哩哔哩_bilibili
Android 根底课程 - 热修复 / 热更新技术原理_哔哩哔哩_bilibili
本文转自 https://juejin.cn/post/7052511816101920804,如有侵权,请分割删除。