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();
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

涉及到的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;
            }
        }
    };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

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

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

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

猜你喜欢

转载自blog.csdn.net/mafei852213034/article/details/77740366