注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好。

原文链接:http://developer.android.com/training/managing-audio/audio-focus.html


有很多应用会要播放音频,所以他们之间如何交互是很重要的。为了防止每个音乐播放器应用在同一时间播放,Android使用音频焦点来调整音频的播放。也就是说,只有获得了音频焦点的应用可以播放音频。

在你的应用开始播放音频之前,它应该需求并接收音频焦点。另外,它应该知道如何监听音频焦点丢失的情况,并在发生焦点丢失时能够正确地响应。


一). 需求音频焦点

在你的应用开始播放音频之前,它应该获取要使用音频流的焦点。这需要调用requestAudioFocus()方法。如果请求成功,那么会返回AUDIOFOCUS_REQUEST_GRANTED。

你必须指定你正在使用的是什么流,和你期望获得暂时的还是永久的音频焦点。当你只需要短时间的播放音频时(比如当播放一些使用导航时),那么应该请求暂时焦点。当你计划在可预测的未来持续播放音频时(比如播放音乐),那么你应该请求永久焦点。

下面的代码请求音乐音频流的永久焦点。你必须在你开始播放之前就请求音频焦点,比如当用户按下了播放键,或下一级别游戏的背景音乐开始时:

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.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
// Start playback.
}

一旦你完成了播放,务必记得要调用abandonAudioFocus(),这将会告知系统你不再需要焦点并且注销相关联的AudioManager.OnAudioFocusChangeListener。对于放弃了暂时焦点的情况,这回允许任何被打断的应用继续播放。

// Abandon audio focus when playback complete
am.abandonAudioFocus(afChangeListener);

当请求暂时音频焦点时,你可以有一个额外的选项:你是否希望启用“ducking”。一般的,当一个正常的应用丢失了音频焦点后,它会立马停止播放。通过请求允许“ducking”的暂时音频焦点,相当于你告知了其他应用:你们可以继续播放,但是他们需要在焦点回到他们手中之前降低音量。

// Request audio focus for playback
int result = am.requestAudioFocus(afChangeListener,
// Use the music stream.
AudioManager.STREAM_MUSIC,
// Request permanent focus.
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK); if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
// Start playback.
}

"Ducking"对于那些间歇性使用音频流的应用特别有用,比如那些语音驾驶提醒的。

在任何时候,若其他的应用像上面描述的那样请求音频焦点,它所选择的永久的活暂时的(有或没有“ducking”选项)音频焦点,在请求时都会被你注册的监听器所接收。


二). 处理焦点丢失

如果你的应用请求了音频焦点,它遵守这样的规定:如果其他应用请求焦点,它会按照次序丢失焦点。你的应用应该如何响应焦点丢失取决于丢失的方式。

在你请求音频焦点时,注册的音频焦点变更监听器中onAudioFocusChange()回调函数会接收一个参数,它描述焦点变化的事件。特别地,可能的焦点丢失事件反映的是上一部分的焦点请求类型,永久丢失,暂时丢失以及允许“ducking”的暂时焦点。

一般而言,一个暂时的音频焦点丢失会导致你的应用音频流没有声音,但其它方面会保持不变。你应该持续检查音频焦点的变化,并准备在你重新获得焦点时,从暂停额位置继续播放。

如果音频焦点要永久丢失,它假定另一个应用正在被用来听音频,并且你的应用应该将自己终止。在实际的场景下,这意味着停止播放,移除媒体按键监听,允许新的音频播放器单独处理这些事件,并放弃你的音频焦点。这样之后,在你恢复播放音频之前你只能期望用户的行为(如在你应用中按下播放键)。

在下面的代码中,我们停止播放器或者我们的媒体播放对象,如果音频焦点丢失是暂时的,另外恢复它当我们要恢复焦点时。如果焦点丢失是永久的,那么代码会注销我们的媒体按键时间接收器,并停止检查音频焦点变更。

OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {
public void onAudioFocusChange(int focusChange) {
if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT
// Pause playback
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
// Resume playback
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
am.abandonAudioFocus(afChangeListener);
// Stop playback
}
}
};

对于允许ducking而丢失焦点的情况,那么你可以使用“ducking”而不是停止播放。


三). Duck!

Ducking是降低你音频外放的音量使得另一个应用的暂时性音频更容易听见,这样就不用暂停你自己应用的播放了。

下面的代码在暂时丢失焦点时降低我们播放器的音量,并在恢复焦点后,恢复音量。

OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {
public void onAudioFocusChange(int focusChange) {
if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
// Lower the volume
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
// Raise it back to normal
}
}
};

音频焦点的丢失是要响应广播中最重要的,但它不是唯一一个最重要的。系统会发送一系列的intent来让你改变用户的音频体验。下一节课将会讲授如何监听它们来提供用户的音频体验。

【Android Developers Training】 45. 控制音频焦点的更多相关文章

  1. 【Android Developers Training】 43. 序言:管理音频播放

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  2. 【Android Developers Training】 44. 控制你应用的音量和播放

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  3. 【Android Developers Training】 50. 控制相机

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  4. 【Android Developers Training】 46. 处理音频外放设备

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  5. 【Android Developers Training】 83. 实现高效网络访问来优化下载

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  6. 【Android Developers Training】 108. 使用模拟定位进行测试

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  7. 【Android Developers Training】 105. 显示一个位置地址

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  8. 【Android Developers Training】 104. 接受地点更新

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  9. 【Android Developers Training】 101. 显示快速联系人挂件(Quick Contact Badge)

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

随机推荐

  1. flume集群日志收集

    一.Flume简介 Flume是一个分布式的.高可用的海量日志收集.聚合和传输日志收集系统,支持在日志系统中定制各类数据发送方(如:Kafka,HDFS等),便于收集数据.其核心为agent,agen ...

  2. HourRank 20

    第一题略 第二题组合数学 s1 = min(cnt['a'],cnt['b']), s2 = min(cnt['c'],cnt['d']), b1 = max(cnt['a'],cnt['b']), ...

  3. 使用公共 Registry - 每天5分钟玩转 Docker 容器技术(19)

    保存和分发镜像的最直接方法就是使用 Docker Hub. Docker Hub 是 Docker 公司维护的公共 Registry.用户可以将自己的镜像保存到 Docker Hub 免费的 repo ...

  4. .net很简介的操作json数组

    using Newtonsoft.Json.Linq;//添加的引用,Newtonsoft.dll可以到guget里面下载 string json="json字符串" JObjec ...

  5. struts2.1.6教程五、拦截器

    在前面我们已经初步使用过拦截器,下面继续细细探讨. 1.概述strust2中的拦截器 拦截器是Struts2框架的核心,它主要完成解析请求参数.将请求参数赋值给Action属性.执行数据校验.文件上传 ...

  6. 决策树模型比较:C4.5,CART,CHAID,QUEST

    (1)C4.5算法的特点为: 输入变量(自变量):为分类型变量或连续型变量. 输出变量(目标变量):为分类型变量. 连续变量处理:N等分离散化. 树分枝类型:多分枝. 分裂指标:信息增益比率gain ...

  7. 写给Android App开发人员看的Android底层知识(7)

    (十二)ContentProvider (1)ContentProvider是什么? ContentProvider,简称CP. 做App开发的同学,尤其是电商类App,对CP并不熟悉,对这个概念的最 ...

  8. 为什么说上ERP找死?

    长期以来,管理软件领域流行着这样一句话“不上ERP等死,上了ERP找死”.根据为十九年管理软件开发的经验来看,“不上ERP等死”这句话不敢苟同,但“上了ERP找死”这句话倒有些同感.上ERP虽然不一定 ...

  9. VR全景智慧城市——商家的需求才是全景市场的核心竞争力

    消费者视角痛点:比如酒店消费行业,很多消费者在预订酒店过程中,都遇到过这样的场景:网上照片里酒店房间看着宽敞明亮,格调不凡,感觉非常喜欢,等真正推开房门插上房卡一看,却大失所望.在酒店行业,网上照片和 ...

  10. java7增强的try语句关闭资源

    java7增强的try语句关闭资源 传统的关闭资源方式 import java.io.FileInputStream; import java.io.FileOutputStream; import ...