首页 > 解决方案 > onServicesDiscovered() 回调没有被调用

问题描述

我正在构建一个 android 应用程序来连接和读取基于 Arduino 的 BLE 设备的数据。我能够找到并连接到设备,但由于某种原因,无论我多么努力,onServicesDiscovered() 回调函数都不会被调用。我已经尝试在发现之前等待 600 毫秒,甚至 1.5 秒,我确保 discoverServices() 命令在 UI 线程上运行,并且多次重做蓝牙代码。我之前能够成功地做到这一点,并且该函数将被调用,但我想将所有蓝牙代码放在它自己单独的类文件中以清理我的主要活动文件,我这样做没有创建备份,而这个是我的问题开始的地方。因此,我尝试在我的主文件中再次重做,但无济于事。

编辑:我发布的原始代码无论如何都不起作用,所以这是更新的代码,但有同样的错误。

这是我的代码(这是我的主要活动文件):

package com.example.androidrf;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.widget.TextView;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;

import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;

import org.jetbrains.annotations.NotNull;

import java.util.Collections;
import java.util.UUID;

import static android.bluetooth.BluetoothDevice.TRANSPORT_LE;

public class MainActivity extends AppCompatActivity {
    public TabLayout tabLayout;
    public ViewPager2 viewPager;
    public TextView connectionWarning;

    // Bluetooth Variables
    BluetoothManager bluetoothManager;

    BluetoothAdapter bluetoothAdapter;

    private static final int REQUEST_ENABLE_BT = 1;

        // UUID's
    private String arduinoName;
    private String serviceId;
    private String ledCharacteristicId;
    private String numberCharacteristicId;
    private UUID serviceUUID;
    private UUID ledCharUUID;
    private UUID numCharUUID;

        // Scan Settings
    private ScanFilter scanFilter;
    private ScanSettings scanSettings;

    // GATT, Characteristics, and Services
    private BluetoothGatt gatt;
    private BluetoothGattService service;
    private BluetoothGattCharacteristic ledChar;
    private BluetoothGattCharacteristic numberChar;

    // Scanning Related Code
    private final BluetoothLeScanner bluetoothLeScanner = BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner();
    private boolean mScanning;
    private final Handler handler = new Handler();

    // Stops scanning after 10 seconds.
    private static final long SCAN_PERIOD = 10000;

    private void scanDevices(boolean forceStop) {
        if (forceStop) {
            mScanning = false;
            bluetoothLeScanner.stopScan(scanCallback);
        }
    }

    private void scanDevices() {
        if (!mScanning) {
            // Stops scanning after a pre-defined scan period.
            handler.postDelayed(() -> {
                if (!mScanning) return;
                mScanning = false;
                bluetoothLeScanner.stopScan(scanCallback);
            }, SCAN_PERIOD);
            if (deviceFound) return;
            mScanning = true;
            bluetoothLeScanner.startScan(Collections.singletonList(scanFilter), scanSettings, scanCallback);
        } else {
            mScanning = false;
            bluetoothLeScanner.stopScan(scanCallback);
        }
    }

    // Scan Callback
    private boolean deviceFound;

    private final ScanCallback scanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            super.onScanResult(callbackType, result);
            if (deviceFound) {
                bluetoothLeScanner.flushPendingScanResults(this);
                if (mScanning) scanDevices(true);
                return;
            }
            if (result.getScanRecord().getDeviceName().equals(arduinoName)) {
                deviceFound = true;
                new Handler(Looper.getMainLooper()).postDelayed(() -> gatt = result.getDevice().connectGatt(getBaseContext(), false, gattCallback, TRANSPORT_LE), 600);
                //gatt.connect();
            }
        }
    };

    // GATT Callback
    private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            super.onConnectionStateChange(gatt, status, newState);
            Log.d("Gatt Services", "Status: " + status + ", newState: " + newState);
            if (status == BluetoothGatt.GATT_SUCCESS) {
                if (newState == BluetoothGatt.STATE_CONNECTED) {
                    new Handler(Looper.getMainLooper()).postDelayed(() -> {
                        Log.d("Gatt Services", "Discovering Services");
                        runOnUiThread(gatt::discoverServices);
                    }, 600);
                }
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            super.onServicesDiscovered(gatt, status);
            Log.d("Gatt Characteristics", "Success");
            if (status == BluetoothGatt.GATT_SUCCESS) {
                ledChar = gatt.getService(serviceUUID).getCharacteristic(ledCharUUID);
                numberChar = gatt.getService(serviceUUID).getCharacteristic(numCharUUID);
                gatt.setCharacteristicNotification(numberChar, true);

            }
        }

//      @Override
//      public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
//          super.onCharacteristicRead(gatt, characteristic, status);
//      }
//
//      @Override
//      public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
//          super.onCharacteristicWrite(gatt, characteristic, status);
//      }
//
//      @Override
//      public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
//          super.onCharacteristicChanged(gatt, characteristic);
//      }
//
//      @Override
//      public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
//          super.onReadRemoteRssi(gatt, rssi, status);
//      }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
        connectionWarning = findViewById(R.id.warningLabel);

        //Bluetooth ------------------------------------------------------------------------------------------

        bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        bluetoothAdapter = bluetoothManager.getAdapter();

        arduinoName = getResources().getString(R.string.arduino_name);
        serviceId = getResources().getString(R.string.service_id);
        ledCharacteristicId = getResources().getString(R.string.led_char_id);
        numberCharacteristicId = getResources().getString(R.string.num_char_id);

        serviceUUID = UUID.fromString(serviceId);
        ledCharUUID = UUID.fromString(ledCharacteristicId);
        numCharUUID = UUID.fromString(numberCharacteristicId);

        scanFilter = new ScanFilter.Builder().setDeviceName(arduinoName).build();
        scanSettings = new ScanSettings.Builder()
                .setScanMode(ScanSettings.SCAN_MODE_BALANCED)
                //.setCallbackType(ScanSettings.CALLBACK_TYPE_FIRST_MATCH)
                .build();

        if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) {
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
        }

        scanDevices();

        //ViewPager ------------------------------------------------------------------------------------------
        sectionsPagerAdapter SectionsPagerAdapter = new sectionsPagerAdapter(this);
        viewPager = findViewById(R.id.view_pager);
        viewPager.setAdapter(SectionsPagerAdapter);

        // Tab Layout ----------------------------------------------------------------------------------------
        tabLayout = findViewById(R.id.tabs);
        new TabLayoutMediator(tabLayout, viewPager, true, true, (tab, position) -> {
            String text = "";

            switch(position) {
                case 0:
                    text = getString(R.string.tab_text_1);
                    break;
                case 1:
                    text = getString(R.string.tab_text_2);
                    break;
            }
            tab.setText(text);
        }).attach();
    }

    private static class sectionsPagerAdapter extends FragmentStateAdapter {
        public sectionsPagerAdapter(FragmentActivity fa) {
            super(fa);
        }

        @NotNull
        @Override
        public Fragment createFragment(int position) {
            Fragment fragment = null;
            switch(position) {
                case 0:
                    fragment = new HomeFragment();
                    break;
                case 1:
                    fragment = new SettingsFragment();
                    break;
            }
            return fragment;
        }

        @Override
        public int getItemCount() {
            return 2;
        }
    }

    @Override
    public void onStop() {
        super.onStop();
        if (gatt == null) return;
        gatt.close();
        gatt = null;
    }
}

标签: javaandroidbluetoothbluetooth-lowenergy

解决方案


为什么要确保在 UI 线程上运行 discoverServices() 方法?这是一个异步操作。试试新线程。


推荐阅读