转载请注明出处:http://www.cnblogs.com/landptf/p/6384112.html


2017年开年第一篇博客,很早就想总结一下Android音频的相关知识。
今天我们先来看一下音频焦点的相关内容,分为上下篇,上篇主要介绍音频焦点在媒体类应用中的使用,下篇进行源码分析,我们学习源码不仅仅是为了更深入的了解,更主要的目的是学习Android的设计架构,为我们在平时开发过程中提供一些优秀的设计思想。
一 焦点在Android应用中的作用
我们的手机里经常会安装一些媒体类的应用,例如网易云音乐,QQ音乐,爱奇艺视频,优酷视频等等,你有没有想过,当我们听QQ音乐的歌曲时,切换到网易云音乐播放歌曲,或者打开爱奇艺观看视频时,QQ音乐播放的歌曲就会暂停,这是为什么呢?又是如何实现的呢?如果不暂停会是什么效果呢?
以上这些疑问都可以用音频焦点来解释,在下面的内容中你将找到答案。
二 焦点讲解
众所周知Android是一个开放的系统,为了协调各媒体应用之间的关系,Android增加了音频焦点管理机制,各应用开发者应尽量遵循该机制进行开发。
我们通过一个例子来讲解Android的焦点机制。
新建一个Activity,在其中增加一个播放暂停按钮,来控制音乐播放。
看一下部分关键代码,全部代码在文末会给出

private void initData() {
//1 初始化AudioManager对象
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
//2 申请焦点
mAudioManager.requestAudioFocus(mAudioFocusChange, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
AssetFileDescriptor fileDescriptor;
try {
//3 获取音频文件,我从网上下载的歌曲,放到了assets目录下
fileDescriptor = this.getAssets().openFd("littlelucky.mp3");
//4 实例化MediaPlayer对象
mMediaPlayer = new MediaPlayer();
//5 设置播放流类型
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
//6 设置播放源,有多个参数可以选择,具体参考相关文档,本文旨在介绍音频焦点
mMediaPlayer.setDataSource(fileDescriptor.getFileDescriptor(),
fileDescriptor.getStartOffset(),
fileDescriptor.getLength());
//7 设置循环播放
mMediaPlayer.setLooping(true);
//8 准备监听
mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
//9 准备完成后自动播放
mMediaPlayer.start();
}
});
//10 异步准备
mMediaPlayer.prepareAsync();
} catch (IOException e) {
e.printStackTrace();
}
}

涉及到的MediaPlayer播放音乐流程请自行查询相关文档,不在本文介绍范围
我们重点看一下第2步 申请焦点
通过AudioManager对象调用requestAudioFocus方法,有三个参数
OnAudioFocusChangeListener l,int streamType,int durationHint
1 焦点变化的监听器

private AudioManager.OnAudioFocusChangeListener mAudioFocusChange = new AudioManager.OnAudioFocusChangeListener() {
@Override
public void onAudioFocusChange(int focusChange) {
switch (focusChange){
case AudioManager.AUDIOFOCUS_LOSS:
//长时间丢失焦点,当其他应用申请的焦点为AUDIOFOCUS_GAIN时,
//会触发此回调事件,例如播放QQ音乐,网易云音乐等
//通常需要暂停音乐播放,若没有暂停播放就会出现和其他音乐同时输出声音
Log.d(TAG, "AUDIOFOCUS_LOSS");
stop();
//释放焦点,该方法可根据需要来决定是否调用
//若焦点释放掉之后,将不会再自动获得
mAudioManager.abandonAudioFocus(mAudioFocusChange);
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
//短暂性丢失焦点,当其他应用申请AUDIOFOCUS_GAIN_TRANSIENT或AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE时,
//会触发此回调事件,例如播放短视频,拨打电话等。
//通常需要暂停音乐播放
stop();
Log.d(TAG, "AUDIOFOCUS_LOSS_TRANSIENT");
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
//短暂性丢失焦点并作降音处理
Log.d(TAG, "AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK");
break;
case AudioManager.AUDIOFOCUS_GAIN:
//当其他应用申请焦点之后又释放焦点会触发此回调
//可重新播放音乐
Log.d(TAG, "AUDIOFOCUS_GAIN");
start();
break;
}
}
};

2 streamType音源类型,在AudioManager中定义

/** 通话 */
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;
/** 通知音 */
public static final int STREAM_NOTIFICATION = AudioSystem.STREAM_NOTIFICATION;
/** @hide 蓝牙电话 */
public static final int STREAM_BLUETOOTH_SCO = AudioSystem.STREAM_BLUETOOTH_SCO;
/** @hide 强制的系统声音 */
public static final int STREAM_SYSTEM_ENFORCED = AudioSystem.STREAM_SYSTEM_ENFORCED;
/** DTMF拨号音 */
public static final int STREAM_DTMF = AudioSystem.STREAM_DTMF;
/** @hide 文本识别音 */
public static final int STREAM_TTS = AudioSystem.STREAM_TTS;

3 durationHint 获得焦点的时间长短
在AudioManager中定义了四种类型

AUDIOFOCUS_GAIN //长时间获得焦点
AUDIOFOCUS_GAIN_TRANSIENT //短暂性获得焦点,用完应立即释放
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK //短暂性获得焦点并降音,可混音播放
AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE //短暂性获得焦点,录音或者语音识别

我们可根据自己的应用的使用场景来合理的配置每个参数,并在焦点变化监听器来做相应的处理。
调试代码已上传github:https://github.com/landptf/BlogDemo

Android音频焦点详解(上)的更多相关文章

  1. android屏幕适配详解

    android屏幕适配详解 官方地址:http://developer.android.com/guide/practices/screens_support.html 一.关于布局适配建议 1.不要 ...

  2. Android系统目录结构详解

    Android系统基于linux内核.JAVA应用,算是一个小巧精致的系统.虽是开源,但不像Linux一般庞大,娇小可亲,于是国内厂商纷纷开发出自己基于Android的操作系统.在此呼吁各大厂商眼光放 ...

  3. android:ToolBar详解

    android:ToolBar详解(手把手教程) 泡在网上的日子 发表于 2014-11-18 12:49 第 124857 次阅读 ToolBar 42 来源 http://blog.mosil.b ...

  4. Android之canvas详解

    首先说一下canvas类: Class Overview The Canvas class holds the "draw" calls. To draw something, y ...

  5. 【转】Android Canvas绘图详解(图文)

    转自:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2012/1212/703.html Android Canvas绘图详解(图文) 泡 ...

  6. Android 核心分析 之八Android 启动过程详解

    Android 启动过程详解 Android从Linux系统启动有4个步骤: (1) init进程启动 (2) Native服务启动 (3) System Server,Android服务启动 (4) ...

  7. Android GLSurfaceView用法详解(二)

    输入如何处理       若是开发一个交互型的应用(如游戏),通常需要子类化 GLSurfaceView,由此可以获取输入事件.下面有个例子: java代码: package eoe.ClearTes ...

  8. Android编译过程详解(一)

    Android编译过程详解(一) 注:本文转载自Android编译过程详解(一):http://www.cnblogs.com/mr-raptor/archive/2012/06/07/2540359 ...

  9. IE8“开发人员工具”使用详解上(各级菜单详解)

    来源: http://www.cnblogs.com/JustinYoung/archive/2009/03/24/kaifarenyuangongju.html IE8“开发人员工具”使用详解上(各 ...

随机推荐

  1. Nginx 中 nginx.conf 详解

    #定义Nginx运行的用户和用户组 user www www; #nginx进程数,建议设置为等于CPU总核心数. worker_processes 8; #全局错误日志定义类型,[ debug | ...

  2. 模块的_name_

    模块的__name__每个模块都有一个名称,在模块中可以通过语句来找出模块的名称.这在一个场合特别有用——就如前面所提到的,当一个模块被第一次输入的时候,这个模块的主块将被运行.假如我们只想在程序本身 ...

  3. mysql、mysqli、pdo使用

    一.php手册关于MySQL的说明:    This extension is not recommended for writing new code. Instead, either themys ...

  4. 关于IP网段间互访的问题—路由是根本(转)

    源: 关于IP网段间互访的问题—路由是根本

  5. eclipse控制台中文乱码解决

    Eclipse控制台中的中文输出乱码问题 博客分类: MySql EclipseTomcatXMLWeb  今天做S2SH集成的例子,所有该设置的地方都设置成了UTF-8,包括tomcat的配置文件s ...

  6. 开启分布式事物DTC

    1.web服务器开启分布式事物配置后,数据库服务器的host文件要设置  “IP  web服务器主机名” 的映射,否则会 出现 “与基础事务管理器的通信失败” #跨网段使用TransactionSco ...

  7. IOS开发-OC学习-protocol(协议)

    在OC语言中,协议是一组方法,里面有两种方法,一种是遵守这个协议的类的实例必须实现的方法,另一种是可以实现也可以不实现的方法. 例如我定义一个学生的协议,这个协议里有两个方法,其中一个是必选的方法:学 ...

  8. 使用React Native来撰写跨平台的App

    React Native 是一个 JavaScript 的框架,用来撰写实时的.可原生呈现 iOS 和 Android 的应用.其是基于 React的,而 React 是 Facebook 的用于构建 ...

  9. android 菜单的总结

    安卓菜单有三种菜单. 选项菜单: 点击系统菜单按钮会触发 上下文菜单:长按屏幕触发 子菜单:某一个菜单的下一级菜单 具体的描叙:http://blog.csdn.net/zqiang_55/artic ...

  10. ubuntu 16.04 php 安装curl方法

    先查看自己的php是否已经安装了curl.方法如下:1.在web服务器目录( Ubuntu下的通常为 /var/www )新建test.php文件2.编辑文件,键入下面一行代码:<?php ph ...