Android 监听系统媒体音量变化

本文介绍了一种在Android系统中监听音量变化的方法,并通过自定义广播接收器实现了对音量调整事件的监听,无论变化是由物理按钮还是音量控制面板触发。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在做 SAPA 适配时由于其直连驱动层不经过 Android 的音量增益控制,所以调节系统媒体音量对音量改变无效。现要调节系统音量时也可以控制播放的音量,那么就需要监听系统音量变化,然后转换成增益给输出数据乘以对应比率从而实现对音量的控制。

一般监听音量多是监听手机物理音量按键的点击事件,但是在音量控制面板拖动音量条改变音量就无法监听。那么我们需要分析无论是按音量键还是拖动音量条,系统都做了什么呢?有什么共性?

参考:Android系统音量变化后会干什么?

从 文中可以知道,当音量变化时,系统会发出广播,所以我们只要监听音量改变的广播就可以了,不用关心具体是哪种方式改变的音量。该广播的 action 为AudioManager.VOLUME_CHANGED_ACTION ,但是该常量被隐藏了,所以直接用 "android.media.VOLUME_CHANGED_ACTION" ,在收到广播时可以通过 AudioManager的getStreamVolume(AudioManager.STREAM_MUSIC) 方法获得当前的音量,也可以从广播中携带的数据获取,我对此做了个封装。

封装如下

package com.ushow.sapademo;
​
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import java.lang.ref.WeakReference;
​
/**
 * Author: Alan Wang.
 * Date: 18/5/29 16:39.
 * Mail: alanwang6584@gmail.com
 */
​
public class VolumeChangeObserver {
​
    private static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION";
    private static final String EXTRA_VOLUME_STREAM_TYPE = "android.media.EXTRA_VOLUME_STREAM_TYPE";
​
    public interface VolumeChangeListener {
        /**
         * 系统媒体音量变化
         * @param volume
         */
        void onVolumeChanged(int volume);
    }
​
    private VolumeChangeListener mVolumeChangeListener;
    private VolumeBroadcastReceiver mVolumeBroadcastReceiver;
    private Context mContext;
    private AudioManager mAudioManager;
    private boolean mRegistered = false;
​
    public VolumeChangeObserver(Context context) {
        mContext = context;
        mAudioManager = (AudioManager) context.getApplicationContext()
                .getSystemService(Context.AUDIO_SERVICE);
    }
​
    /**
     * 获取当前媒体音量
     * @return
     */
    public int getCurrentMusicVolume() {
        return mAudioManager != null ? mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC) : -1;
    }
​
    /**
     * 获取系统最大媒体音量
     * @return
     */
    public int getMaxMusicVolume() {
        return mAudioManager != null ? mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) : 15;
    }
​
    public VolumeChangeListener getVolumeChangeListener() {
        return mVolumeChangeListener;
    }
​
    public void setVolumeChangeListener(VolumeChangeListener volumeChangeListener) {
        this.mVolumeChangeListener = volumeChangeListener;
    }
​
    /**
     * 注册音量广播接收器
     * @return
     */
    public void registerReceiver() {
        mVolumeBroadcastReceiver = new VolumeBroadcastReceiver(this);
        IntentFilter filter = new IntentFilter();
        filter.addAction(VOLUME_CHANGED_ACTION);
        mContext.registerReceiver(mVolumeBroadcastReceiver, filter);
        mRegistered = true;
    }
​
    /**
     * 解注册音量广播监听器,需要与 registerReceiver 成对使用
     */
    public void unregisterReceiver() {
        if (mRegistered) {
            try {
                mContext.unregisterReceiver(mVolumeBroadcastReceiver);
                mVolumeChangeListener = null;
                mRegistered = false;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
​
    private static class VolumeBroadcastReceiver extends BroadcastReceiver {
        private WeakReference<VolumeChangeObserver> mObserverWeakReference;
​
        public VolumeBroadcastReceiver(VolumeChangeObserver volumeChangeObserver) {
            mObserverWeakReference = new WeakReference<>(volumeChangeObserver);
        }
​
        @Override
        public void onReceive(Context context, Intent intent) {
            //媒体音量改变才通知
            if (VOLUME_CHANGED_ACTION.equals(intent.getAction())
                    && (intent.getIntExtra(EXTRA_VOLUME_STREAM_TYPE, -1) == AudioManager.STREAM_MUSIC)) {
                VolumeChangeObserver observer = mObserverWeakReference.get();
                if (observer != null) {
                    VolumeChangeListener listener = observer.getVolumeChangeListener();
                    if (listener != null) {
                        int volume = observer.getCurrentMusicVolume();
                        if (volume >= 0) {
                            listener.onVolumeChanged(volume);
                        }
                    }
                }
            }
        }
    }
}
​

对外暴露有以下几个方法:

  • VolumeChangeObserver(Context context):构造函数;

  • VolumeChangeListener:音量改变接口,当媒体音量变化时会调用其 onVolumeChanged(int volume) 方法;

  • setVolumeChangeListener(VolumeChangeListener volumeChangeListener):设置音量改变的监听器;

  • getCurrentMusicVolume():获取当前媒体音量;

  • registerReceiver():注册接收器;

  • unregisterReceiver():解注册接收器

调用逻辑如下

package com.ushow.sapademo;
​
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
​
//实现 VolumeChangeListener 接口
public class MainActivity extends AppCompatActivity implements VolumeChangeObserver.VolumeChangeListener {
    private final static String TAG = MainActivity.class.getSimpleName();
​
    private VolumeChangeObserver mVolumeChangeObserver;
​
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
​
        //实例化对象并设置监听器
        mVolumeChangeObserver = new VolumeChangeObserver(this);
        mVolumeChangeObserver.setVolumeChangeListener(this);
        int initVolume = mVolumeChangeObserver.getCurrentMusicVolume();
        Log.e(TAG, "initVolume = " + initVolume);
    }
​
    @Override
    protected void onResume() {
        //注册广播接收器
        mVolumeChangeObserver.registerReceiver();
        super.onResume();
    }
​
    @Override
    protected void onPause() {
        //解注册广播接收器
        mVolumeChangeObserver.unregisterReceiver();
        super.onPause();
    }
​
    @Override
    public void onVolumeChanged(int volume) {
        //系统媒体音量改变时的回调
        Log.e(TAG, "onVolumeChanged()--->volume = " + volume);
    }
}
​

原文链接:https://blog.youkuaiyun.com/u011520181/article/details/80529414

### 关于 Android 媒体音量变化广播接收器 当涉及监听媒体音量变化时,`AudioManager.ACTION_AUDIO_BROADCAST`并不是标准的广播动作名称;通常情况下,开发者会关注的是音频焦点(audio focus)以及耳机插拔等事件。对于具体的音量改变通知,Android并没有提供专门针对此目的的标准广播意图。 然而,如果目标是在应用程序内部监测到音量键被按下从而导致音量发生变化,则可以通过重写Activity中的`onKeyDown()`方法来捕捉这一行为[^3]: ```java @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP){ // 处理音量增减逻辑 return true; } return super.onKeyDown(keyCode, event); } ``` 另外一种间接的方式是利用`AudioManager`类提供的APIs获取当前设备上的流(stream)状态,并定期轮询比较其值是否有变动。不过这种方式效率较低且不够实时。 由于从 Android O 开始引入了对后台服务和隐式广播接收者的严格限制政策,即使尝试注册全局级别的广播接收者也无法接收到诸如 `Intent.ACTION_HEADSET_PLUG` 或 `AudioManager.ACTION_AUDIO_BECOMING_NOISY` 这样的隐式广播消息。 因此,对于想要响应特定类型的音频相关事件的应用程序来说,更推荐的做法是在前台进程中动态地注册一个本地广播接收者实例,以便能够及时处理来自系统的相应通知。需要注意的是,这种方法仅适用于那些已经在运行的应用组件内有效工作的情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值