• I don't know how to create (initialize) a "BluetoothHeadset" object. It seems that I need to use "getProfileProxy ()" but I need a sample code to find out how I need to create and pass the parameters.
  • android
    bluetooth
    user688429
    user688429
    发布于 2011-04-02
    2 个回答
    Team Pannous
    Team Pannous
    发布于 2022-10-24
    0 人赞同

    You need to implement BluetoothProfile.ServiceListener :

    BluetoothProfile.ServiceListener b = new BlueToothListener();
                boolean profileProxy = BluetoothAdapter.getDefaultAdapter()
                        .getProfileProxy(Handler.bot, b, BluetoothProfile.HEADSET);
    public class BlueToothListener implements ServiceListener {
            public static BluetoothHeadset headset;
            public static BluetoothDevice bluetoothDevice;
        @Override
        public void onServiceDisconnected(int profile) {// dont care
            headset = null;
        @Override
        public void onServiceConnected(int profile,
                BluetoothProfile proxy) {// dont care
            try {
                Debugger.test("BluetoothProfile onServiceConnected "+proxy);
                if (proxy instanceof BluetoothHeadset)
                    headset = ((BluetoothHeadset) proxy);
                else// getProfileProxy(Handler.bot, b, BluetoothProfile.HEADSET); 
                    return;// ^^ => NEVER
                List<BluetoothDevice> connectedDevices = proxy
                        .getConnectedDevices();
                for (BluetoothDevice device : connectedDevices) {
                    Debugger.log("BluetoothDevice found :" + device);
                    bluetoothDevice = device;
                    int connectionState = headset.getConnectionState(bluetoothDevice);
                    Debugger.log("BluetoothHeadset connectionState "+connectionState);//2 == OK
                    boolean startVoiceRecognition = headset
                            .startVoiceRecognition(device);
                    if (startVoiceRecognition) {
                        Debugger
                                .log("BluetoothHeadset init Listener OK");
                        return;
                        Notify.popup("Bluetooth headset can't start speech recognition");
            } catch (Exception e) {
        
    当一个蓝牙设备连接/断开时,'onServiceConnected'从未被调用。
    @VineeshTP有什么解决办法吗?
    事实上,这在每次调用中只被调用一次。与轮询类似。这个没有回调吗?
    android developer
    android developer
    发布于 2022-10-24
    0 人赞同

    对BT状态的监控确实可以通过轮询来完成。下面是我的做法(完整的样本 here ) .请注意,这只是一个样本,你应该更好地管理投票。

    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    

    Gradle

    implementation 'androidx.core:core-ktx:1.9.0'
    implementation 'com.google.android.material:material:1.7.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
    implementation "androidx.work:work-runtime-ktx:2.7.1"
    

    视觉效果。

    @UiThread
    class MainActivityViewModel(application: Application) : BaseViewModel(application) {
        private val bluetoothAdapter: BluetoothAdapter =
            context.getSystemService<BluetoothManager>()!!.adapter
        private var bluetoothHeadsetProfile: BluetoothProfile? = null
        val connectedDevicesLiveData =
            DistinctLiveDataWrapper(MutableLiveData<ConnectedDevicesState>(ConnectedDevicesState.Idle))
        val bluetoothTurnedOnLiveData = DistinctLiveDataWrapper(MutableLiveData<Boolean?>(null))
        val isConnectedToBtHeadsetLiveData = DistinctLiveDataWrapper(MutableLiveData<Boolean?>(null))
        private val pollingBtStateRunnable: Runnable
        init {
            updateBtStates()
            pollingBtStateRunnable = object : Runnable {
                override fun run() {
                    updateBtStates()
                    handler.postDelayed(this, POLLING_TIME_IN_MS)
            // Establish connection to the proxy.
            val serviceListener = object : BluetoothProfile.ServiceListener {
                override fun onServiceConnected(profile: Int, bluetoothProfile: BluetoothProfile) {
                    this@MainActivityViewModel.bluetoothHeadsetProfile = bluetoothProfile
                    handler.removeCallbacks(pollingBtStateRunnable)
                    pollingBtStateRunnable.run()
                override fun onServiceDisconnected(profile: Int) {
                    handler.removeCallbacks(pollingBtStateRunnable)
                    updateBtStates()
            bluetoothAdapter.getProfileProxy(context, serviceListener, BluetoothProfile.HEADSET)
            onClearedListeners.add {
                this.bluetoothHeadsetProfile?.let { bluetoothProfile ->
                    bluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, bluetoothProfile)
                handler.removeCallbacks(pollingBtStateRunnable)
        fun initWithLifecycle(lifecycle: Lifecycle) {
            lifecycle.addObserver(object : DefaultLifecycleObserver {
                override fun onResume(owner: LifecycleOwner) {
                    super.onResume(owner)
                    pollingBtStateRunnable.run()
                override fun onPause(owner: LifecycleOwner) {
                    super.onPause(owner)
                    handler.removeCallbacks(pollingBtStateRunnable)
        @UiThread
        private fun updateBtStates() {
            //        Log.d("AppLog", "updateBtStates")
            val isBlueToothTurnedOn = bluetoothAdapter.state == BluetoothAdapter.STATE_ON
            bluetoothTurnedOnLiveData.value = isBlueToothTurnedOn
            if (!isBlueToothTurnedOn) {
                connectedDevicesLiveData.value = ConnectedDevicesState.BluetoothIsTurnedOff
                isConnectedToBtHeadsetLiveData.value = false
                return
            val isConnectedToBtHeadset = try {
                bluetoothAdapter.getProfileConnectionState(BluetoothProfile.HEADSET) == BluetoothAdapter.STATE_CONNECTED
            } catch (e: SecurityException) {
            isConnectedToBtHeadsetLiveData.value = isConnectedToBtHeadset
            val bluetoothProfile = bluetoothHeadsetProfile
            if (bluetoothProfile != null) {
                if (ActivityCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED) {
                    val connectedDevicesSet = bluetoothProfile.connectedDevices.toHashSet()
                    val previousConnectedDevices =
                        (connectedDevicesLiveData.value as? ConnectedDevicesState.GotResult)?.connectedDevices
                    if (previousConnectedDevices == null || previousConnectedDevices != connectedDevicesSet)
                        connectedDevicesLiveData.value =
                            ConnectedDevicesState.GotResult(connectedDevicesSet)
                } else {
                    connectedDevicesLiveData.value =
                        ConnectedDevicesState.NeedBlueToothConnectPermission
            } else {
                connectedDevicesLiveData.value = ConnectedDevicesState.Idle
        companion object {
            private const val POLLING_TIME_IN_MS = 500L
    

    主要活动.kt

    class MainActivity : AppCompatActivity() {
        private lateinit var viewModel: MainActivityViewModel
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            viewModel = ViewModelProvider(this)[MainActivityViewModel::class.java]
            viewModel.initWithLifecycle(lifecycle)
            viewModel.bluetoothTurnedOnLiveData.observe(this) {
                Log.d("AppLog", "MainActivity bluetoothTurnedOnLiveData BT turned on? $it")
            viewModel.isConnectedToBtHeadsetLiveData.observe(this) {
                Log.d("AppLog", "MainActivity isConnectedToBtHeadsetLiveData BT headset connected? $it")
            viewModel.connectedDevicesLiveData.observe(this) {
                Log.d("AppLog", "MainActivity connectedDevicesLiveData devices: $it")
            findViewById<View>(R.id.grantBtPermission).setOnClickListener {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                    requestPermissions(arrayOf(Manifest.permission.BLUETOOTH_CONNECT), 1)
    

    ConnectedDevicesState.kt

    sealed class ConnectedDevicesState {
        object Idle : ConnectedDevicesState() {
            override fun toString(): String {
                if (BuildConfig.DEBUG)
                    return "Idle"
                return super.toString()
        class GotResult(@Suppress("MemberVisibilityCanBePrivate") val connectedDevices: Set<BluetoothDevice>) : ConnectedDevicesState() {
            override fun toString(): String {
                if (BuildConfig.DEBUG) {
                    return "GotResult: connectedDevices:${
                        connectedDevices.map {
                            try {
                                it.name
                            } catch (e: SecurityException) {
                                it.address
                return super.toString()
        object BluetoothIsTurnedOff : ConnectedDevicesState() {
            override fun toString(): String {
                if (BuildConfig.DEBUG)
                    return "BluetoothIsTurnedOff"
                return super.toString()
        object NeedBlueToothConnectPermission : ConnectedDevicesState() {
            override fun toString(): String {
                if (BuildConfig.DEBUG)
                    return "NeedBlueToothConnectPermission"
                return super.toString()
    

    DistinctLiveDataWrapper.kt

    class DistinctLiveDataWrapper<T>(@Suppress("MemberVisibilityCanBePrivate") val mutableLiveData: MutableLiveData<T>) {
        @Suppress("MemberVisibilityCanBePrivate")
        val distinctLiveData = Transformations.distinctUntilChanged(mutableLiveData)
        var value: T?
            @UiThread
            set(value) {
                mutableLiveData.value = value
            get() {
                return mutableLiveData.value
        @AnyThread
        fun postValue(value: T) {
            mutableLiveData.postValue(value)
        fun observe(lifecycleOwner: LifecycleOwner, observer: Observer<in T>) {
            distinctLiveData.observe(lifecycleOwner, observer)
    

    基准视图模型.kt

    /**usage: class MyViewModel(application: Application) : BaseViewModel(application)
     * getting instance:    private lateinit var viewModel: MyViewModel
     * viewModel=ViewModelProvider(this).get(MyViewModel::class.java)*/
    abstract class BaseViewModel(application: Application) : AndroidViewModel(application) {
        @Suppress("MemberVisibilityCanBePrivate")
        var isCleared = false
        @Suppress("MemberVisibilityCanBePrivate")
        val onClearedListeners = ArrayList<Runnable>()
        @Suppress("unused")
        @SuppressLint("StaticFieldLeak")
        val context: Context = application.applicationContext
        @Suppress("unused")
        val handler = Handler(Looper.getMainLooper())
        override fun onCleared() {
            super.onCleared()