Android:有线耳机拔出或蓝牙耳机断开连接,暂停播放

发布时间:2024年01月05日

? ? 当我们正在“专注学习”的过程中,如果不小心拔掉了耳机线或者断开蓝牙耳机的连接,突然之间我们APP里正在播放的声音就会打扰到周围的人,如果声音还挺大的话,是不是有些尴尬?所以呢,现在需要实现这么一个功能:在有线耳机拔掉或者蓝牙耳机断开连接时,立刻停止播放。

方式一、通过广播接收器监听有线耳机和蓝牙耳机的状态

步骤1:申请权限

? ? 在工程的AndroidManifest.xml中,添加以下代码:

<manifast xxx>
    ...
    <!-- 获取蓝牙相关权限 -->
    <uses-permission android:name="android.permission.BLUETOOTH" />
    ...
</manifast>

步骤2:注册广播接受器,监听耳机状态变化

? ? 广播注册有两种方式,一种方式是<静态注册>:即在项目的Manifest的文件里注册,经测试,该方式无效。所以可以选择另外一种<动态注册>的方式:在项目的启动页?LanchActivity?或其他合适地方注册广播接收器,笔者采用的方式是单独启动一个后台Service,?在其OnCreate()方法里进行注册。

? ? 不管是在Activity里进行注册,还是在Service里注册,经笔者测试(机型:huawei mate40 pro),在用户完全退出用户界面或运行在后台的情况下,只要不执行 unregisterReceiver 的操作,仍然可以接受到广播。但是笔者建议采用第二种方式,APP 有后台 Service 在运行的情况下,因为被系统回收导致无法接收广播的概率会降低一些,相对来说更加稳定。

public class HeadphoneService extends Service {

    private final HeadphoneReceiver receiver = new HeadphoneReceiver();

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        IntentFilter intentFilter = new IntentFilter();
        //有线耳机
        intentFilter.addAction(Intent.ACTION_HEADSET_PLUG);
        //蓝牙耳机
        intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
        registerReceiver(receiver, intentFilter);
        super.onCreate();
    }

    @Override
    public void onDestroy() {
        unregisterReceiver(receiver);
        super.onDestroy();
    }

}

步骤3:创建接收器,处理状态变化

public class HeadphoneReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        String action = intent.getAction();
        if (Intent.ACTION_HEADSET_PLUG.equals(action)) {
            int state = intent.getIntExtra("state", -1);
            if (state == 0) {
                // 耳机拔出
            } else if (state == 1) {
                // 耳机插入
            }
        } else if (BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {

            BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
            /* 申请权限
            if (ActivityCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
                return;
            }
            */
            //如果应用运行的Android系统版本大于等于12,获取蓝牙状态需要动态申请权限
            int state = adapter.getProfileConnectionState(BluetoothProfile.HEADSET);
            if (state == BluetoothAdapter.STATE_DISCONNECTED) {
                //Bluetooth headset is now disconnected
            }
        }
    }
}

步骤4:?启动Service

// 建议在LaunchActivity的OnCreate()里或其他合适的地方启动服务
Intent intent = new Intent(this, HeadphoneService.class);
startService(intent);

第一种方式虽然可以实现我们的需求,但有两个缺点:

缺点1:如果应用运行的Android系统版本大于等于12,获取蓝牙状态需要动态申请权限;

缺点2:拔出有线耳机或断开蓝牙耳机,会延迟大概一秒钟,才会收到Android的系统广播;

方式二:通过广播接收器监听噪音 - NOISY

    /**
     * Broadcast intent, a hint for applications that audio is about to become
     * 'noisy' due to a change in audio outputs. For example, this intent may
     * be sent when a wired headset is unplugged, or when an A2DP audio
     * sink is disconnected, and the audio system is about to automatically
     * switch audio route to the speaker. Applications that are controlling
     * audio streams may consider pausing, reducing volume or some other action
     * on receipt of this intent so as not to surprise the user with audio
     * from the speaker.
     */
    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    public static final String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY";

? ? ?这段话的大概意思就是,如果耳机线被拔掉或是支持A2DP(蓝牙协议)的音频连接断开后,系统会认为该应用因为声音输出方式改变,导致产生噪音(NOISY),系统会广播该Intent?Action:(ACTION_AUDIO_BECOMING_NOISY),让我们的广播接收器可以做出相应的处理,比如:暂停播放、降低音量等。

步骤1:注册广播接收器

public class HeadphoneService extends Service {

    private final HeadphoneReceiver receiver = new HeadphoneReceiver();

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
        registerReceiver(receiver, intentFilter);
        super.onCreate();
    }

    @Override
    public void onDestroy() {
        unregisterReceiver(receiver);
        super.onDestroy();
    }

}

步骤2:创建接收器,处理状态变化

public class HeadphoneReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        String action = intent.getAction();
        if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(action)) {
            //暂停播放
            pauseAudio();
        }
    }
}

步骤3:?启动Service

// 建议在LaunchActivity的OnCreate()里或其他合适的地方启动服务
Intent intent = new Intent(this, HeadphoneService.class);
startService(intent);

? ? 综上,第二种方式是不是更加简洁呢?既不需要在 Manifest 文件里申明权限,也不需要在运行时动态申请蓝牙权限;而且相对第一种方式没有任何延迟。

文章来源:https://blog.csdn.net/crazestone0614/article/details/135412491
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。