java - BLE 发送/接收;尝试从空对象引用上的字段 'android.bluetooth.BluetoothGattCallback BluetoothLeService.mGattCallback' 读取

标签 java android bluetooth-lowenergy

我对安卓不太了解。我正在尝试通过 BLE 发送数据。我的代码如下->。我从网上得到的 https://developer.android.com/guide/topics/connectivity/bluetooth-le#read

如何正确调用该方法-> mBluetoothService.mBluetoothGatt = device.connectGatt(cntxt, false, mBluetoothService.mGattCallback);这一行出现crash。

    public class BluetoothLeService extends Service {
    private final static String TAG = BluetoothLeService.class.getSimpleName();

    public BluetoothManager mBluetoothManager;
    public BluetoothAdapter mBluetoothAdapter;
    public String mBluetoothDeviceAddress;
    public BluetoothGatt mBluetoothGatt;
    private int mConnectionState = STATE_DISCONNECTED;
    private final IBinder mBinder = new LocalBinder();

    private static final int STATE_DISCONNECTED = 0;
    private static final int STATE_CONNECTING = 1;
    private static final int STATE_CONNECTED = 2;

    public final static String ACTION_GATT_CONNECTED =
            "com.example.bluetooth.le.ACTION_GATT_CONNECTED";
    public final static String ACTION_GATT_DISCONNECTED =
            "com.example.bluetooth.le.ACTION_GATT_DISCONNECTED";
    public final static String ACTION_GATT_SERVICES_DISCOVERED =
            "com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";
    public final static String ACTION_DATA_AVAILABLE =
            "com.example.bluetooth.le.ACTION_DATA_AVAILABLE";
    public final static String EXTRA_DATA =
            "com.example.bluetooth.le.EXTRA_DATA";

    public final static UUID UUID_HEART_RATE_MEASUREMENT =
            UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT);

    // Various callback methods defined by the BLE API.
    public final BluetoothGattCallback mGattCallback =
            new BluetoothGattCallback() {
                @Override
                public void onConnectionStateChange(BluetoothGatt gatt, int status,
                                                    int newState) {
                    String intentAction;
                    if (newState == BluetoothProfile.STATE_CONNECTED) {
                        intentAction = ACTION_GATT_CONNECTED;
                        mConnectionState = STATE_CONNECTED;
                        broadcastUpdate(intentAction);
                        Log.i(TAG, "Connected to GATT server.");
                        Log.i(TAG, "Attempting to start service discovery:" +
                                mBluetoothGatt.discoverServices());

                    } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                        intentAction = ACTION_GATT_DISCONNECTED;
                        mConnectionState = STATE_DISCONNECTED;
                        Log.i(TAG, "Disconnected from GATT server.");
                        broadcastUpdate(intentAction);
                    }
                }

                @Override
                // New services discovered
                public void onServicesDiscovered(BluetoothGatt gatt, int status) {
                    if (status == BluetoothGatt.GATT_SUCCESS) {
                        //broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
                        for (BluetoothGattService gattService : gatt.getServices()) {
                            Log.i(TAG, "onServicesDiscovered: ---------------------");
                            Log.i(TAG, "onServicesDiscovered: service=" + gattService.getUuid());
                            for (BluetoothGattCharacteristic characteristic : gattService.getCharacteristics()) {
                                Log.i(TAG, "onServicesDiscovered: characteristic=" + characteristic.getUuid());

                                if (characteristic.getUuid().toString().equals("0000ffe9-0000-1000-8000-00805f9b34fb")) {

                                    Log.w(TAG, "onServicesDiscovered: found LED");

                                    String originalString = "560D0F0600F0AA";

                                    byte[] b = hexStringToByteArray(originalString);

                                    characteristic.setValue(b); // call this BEFORE(!) you 'write' any stuff to the server
                                    mBluetoothGatt.writeCharacteristic(characteristic);

                                    Log.i(TAG, "onServicesDiscovered: , write bytes?! " + byteToHexStr(b));
                                }
                            }
                        }

                        broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);

                    } else {
                        Log.w(TAG, "onServicesDiscovered received: " + status);
                    }
                }

                @Override
                // Result of a characteristic read operation
                public void onCharacteristicRead(BluetoothGatt gatt,
                                                 BluetoothGattCharacteristic characteristic,
                                                 int status) {
                    if (status == BluetoothGatt.GATT_SUCCESS) {
                        byte[] data = characteristic.getValue();
                        System.out.println("reading");
                        System.out.println(new String(data));
                        broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
                    }
                }
                //...
            };
    private void broadcastUpdate(final String action) {
        final Intent intent = new Intent(action);
        sendBroadcast(intent);
    }

    public static byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                    + Character.digit(s.charAt(i + 1), 16));
        }
        return data;
    }

    public static String byteToHexStr(byte[] bytes) {
        StringBuilder builder = new StringBuilder();
        for (byte b: bytes) {
            builder.append(String.format("%02x", b));
        }
        return builder.toString();
    }


    private void broadcastUpdate(final String action,
                                 final BluetoothGattCharacteristic characteristic) {
        final Intent intent = new Intent(action);

        // This is special handling for the Heart Rate Measurement profile. Data
        // parsing is carried out as per profile specifications.
        if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
            int flag = characteristic.getProperties();
            int format = -1;
            if ((flag & 0x01) != 0) {
                format = BluetoothGattCharacteristic.FORMAT_UINT16;
                Log.d(TAG, "Heart rate format UINT16.");
            } else {
                format = BluetoothGattCharacteristic.FORMAT_UINT8;
                Log.d(TAG, "Heart rate format UINT8.");
            }
            final int heartRate = characteristic.getIntValue(format, 1);
            Log.d(TAG, String.format("Received heart rate: %d", heartRate));
            intent.putExtra(EXTRA_DATA, String.valueOf(heartRate));
        } else {
            // For all other profiles, writes the data formatted in HEX.
            final byte[] data = characteristic.getValue();
            if (data != null && data.length > 0) {
                final StringBuilder stringBuilder = new StringBuilder(data.length);
                for(byte byteChar : data)
                    stringBuilder.append(String.format("%02X ", byteChar));
                intent.putExtra(EXTRA_DATA, new String(data) + "\n" +
                        stringBuilder.toString());
            }
        }
        sendBroadcast(intent);
    }
    public class LocalBinder extends Binder {
        BluetoothLeService getService() {
            return BluetoothLeService.this;
        }
    }
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;/*return null;*/
    }
//...
}

我从外部调用此类方法,如下所示->

    public class DeviceScanActivity extends AppCompatActivity/*ListActivity*/ {
        //private LeDeviceListAdapter mLeDeviceListAdapter;
        public BluetoothAdapter mBluetoothAdapter;
        public /*final*/ BluetoothManager mBluetoothManager;
                /*=(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);;*/
        private BluetoothLeService mBluetoothService;//= new BluetoothLeService();
        public Context cntxt;
        ArrayList<ViewHolder> arrayOfUsers2 = new ArrayList<ViewHolder>();
        private boolean mScanning;
        private boolean mBounded;
        private Handler mHandler;
        ArrayList<String> mylist = new ArrayList<String>();
        private static final int REQUEST_ENABLE_BT = 1;
        // Stops scanning after 10 seconds.
        private static final long SCAN_PERIOD = 50000;
        private static final int PERMISSION_REQUEST_COARSE_LOCATION = 456;

        UsersAdapter adapter;
        @Override
        public void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            //getActionBar().setTitle("abc");

            mHandler = new Handler();
            //this.requestPermissions(rqPerm,req);

            requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
            // Use this check to determine whether BLE is supported on the device.  Then you can
            // selectively disable BLE-related features.
            if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
                Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
                finish();
            }
            // Initializes a Bluetooth adapter.  For API level 18 and above, get a reference to
            // BluetoothAdapter through BluetoothManager.
            /*final BluetoothManager*/ mBluetoothManager =
                    (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
            mBluetoothAdapter = mBluetoothManager.getAdapter();
            // Checks if Bluetooth is supported on the device.
            if (mBluetoothAdapter == null ) {
                Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
                finish();
                return;
            }
            if( !mBluetoothAdapter.isEnabled())
            {
                Intent enableBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                startActivityForResult(getIntent(), 1);
            }
            // Construct the data source

            ArrayList<ViewHolder> arrayOfUsers = new ArrayList<ViewHolder>();

           // Create the adapter to convert the array to views

             adapter = new UsersAdapter(this, arrayOfUsers);
             cntxt=this.getApplicationContext();
            Intent i = new Intent(this, BluetoothLeService.class);
            bindService(this.getIntent(), mConnection, BIND_AUTO_CREATE);; //if checked, start service
            ListView listView = (ListView) findViewById(R.id.mobile_list);
            listView.setAdapter(adapter);
            listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position,
                                        long id) {
                    ViewHolder entry= (ViewHolder) parent.getAdapter().getItem(position);
                    String address = entry.deviceAddress;
                    final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
                    Toast.makeText(cntxt, address, Toast.LENGTH_SHORT).show();
//mBluetoothService.mBluetoothDeviceAddress=address;
                    //mBluetoothService.mBluetoothManager=mBluetoothManager;
                    mBluetoothService.mBluetoothAdapter = mBluetoothAdapter;
                    mBluetoothService.mBluetoothGatt = device.connectGatt(cntxt, false, mBluetoothService.mGattCallback);

                    //Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();
                }});
            ViewHolder newUser2 = new ViewHolder("adtv2","vvg2");
             adapter.add(newUser2);

        }
        ServiceConnection mConnection = new ServiceConnection() {
            @Override
            public void onServiceDisconnected(ComponentName name) {
                //Toast.makeText(Client.this, "Service is disconnected", 1000).show();
                mBounded = false;
                mBluetoothService = null;
            }
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                //Toast.makeText(Client.this, "Service is connected", 1000).show();
                mBounded = true;
                BluetoothLeService.LocalBinder mLocalBinder = (BluetoothLeService.LocalBinder)service;
                mBluetoothService = mLocalBinder.getService();
            }
        };


        private void scanLeDevice(final boolean enable) {
            if (enable) {
                // Stops scanning after a pre-defined scan period.
                ViewHolder newUser2 = new ViewHolder("adtv2","vvg2");
                adapter.add(newUser2);
                mHandler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        mScanning = false;
                        mBluetoothAdapter.stopLeScan(mLeScanCallback);



                        Iterator<ViewHolder> it=arrayOfUsers2.iterator();
                        while(it.hasNext()) {
                            ViewHolder currentX = it.next();
                            adapter.add(currentX);
                        }
                            // Do something with the value

                    }
                }, SCAN_PERIOD);

                mScanning = true;
                mBluetoothAdapter.startLeScan(mLeScanCallback);
            } else {
                mScanning = false;
                mBluetoothAdapter.stopLeScan(mLeScanCallback);
            }
            //invalidateOptionsMenu();
        }
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
            switch (requestCode) {
                case PERMISSION_REQUEST_COARSE_LOCATION: {
                    if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                        // Permission granted, yay! Start the Bluetooth device scan.
                        scanLeDevice(true);
                    } else {
                        // Alert the user that this application requires the location permission to perform the scan.
                    }
                }
            }
        }


        // Device scan callback.
        private BluetoothAdapter.LeScanCallback mLeScanCallback =
                new BluetoothAdapter.LeScanCallback() {

                    @Override
                    public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                //mLeDeviceListAdapter.addDevice(device);
                                //mLeDeviceListAdapter.notifyDataSetChanged();

                                //ViewHolder newUser = new ViewHolder("Nathan", "San Diego");
                                String deviceName=null, deviceAddress=null;
                                if(device!=null)
                                   deviceName= device.getName();
                                if (!(deviceName != null && deviceName.length() > 0))
                                    deviceName = "unknown device";
                                if(device!=null)
                                    deviceAddress= device.getAddress();
                                ViewHolder newUser = new ViewHolder(deviceName, deviceAddress);
                                ViewHolder newUser2 = new ViewHolder("adtv","vvg");
                                if(!arrayOfUsers2.contains(newUser))
                                    arrayOfUsers2.add(newUser);
                                //adapter.add(newUser);
                            }
                        });
                    }
                };
        public class UsersAdapter extends ArrayAdapter<ViewHolder> {


            public UsersAdapter(Context context, ArrayList<ViewHolder> users) {

                super(context, 0, users);

            }



            @Override

            public View getView(int position, View convertView, ViewGroup parent) {

                // Get the data item for this position

                ViewHolder user = getItem(position);


                // Check if an existing view is being reused, otherwise inflate the view

                if (convertView == null) {

                    convertView = LayoutInflater.from(getContext()).inflate(R.layout.bt_details, parent, false);

                }

                // Lookup view for data population

                TextView tvName = (TextView) convertView.findViewById(R.id.DeviceName);

                TextView tvHome = (TextView) convertView.findViewById(R.id.DeviceAddress);

                // Populate the data into the template view using the data object

                tvName.setText(user.deviceName);

                tvHome.setText(user.deviceAddress);

                // Return the completed view to render on screen

                return convertView;

            }

        }
        public class ViewHolder {
            String deviceName;
            String deviceAddress;

            public ViewHolder(String device, String __address) {
                this.deviceName =device;
                this.deviceAddress= __address;
            }
            @Override
            public boolean equals(Object o) {
                if (this == o) return true;
                if (o == null || getClass() != o.getClass()) return false;
                ViewHolder a = (ViewHolder) o;
                return Objects.equals(deviceAddress, a.deviceAddress);
            }
        }



    }

我在列表中获取扫描设备结果。单击该列表中的任何元素时,我会调用 AdapterView.OnItemClickListener()。然后如何向设备发送消息。如何读取这些日志消息。如何知道代码是否已发送消息。如何在其他设备上接收消息。我已经完成了BLE扫描,工作正常。但这里没有添加代码。

日志猫报告如下

FATAL EXCEPTION: main
                                                                                Process: com.example.root.securityalert, PID: 27945
                                                                                java.lang.NullPointerException: Attempt to read from field 'android.bluetooth.BluetoothGattCallback com.example.root.securityalert.BluetoothLeService.mGattCallback' on a null object reference
                                                                                    at com.example.root.securityalert.DeviceScanActivity$1.onItemClick(DeviceScanActivity.java:115)
                                                                                    at android.widget.AdapterView.performItemClick(AdapterView.java:310)
                                                                                    at android.widget.AbsListView.performItemClick(AbsListView.java:1156)
                                                                                    at android.widget.AbsListView$PerformClick.run(AbsListView.java:3147)
                                                                                    at android.widget.AbsListView$3.run(AbsListView.java:4062)
                                                                                    at android.os.Handler.handleCallback(Handler.java:751)
                                                                                    at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                                    at android.os.Looper.loop(Looper.java:154)
                                                                                    at android.app.ActivityThread.main(ActivityThread.java:6165)
                                                                                    at java.lang.reflect.Method.invoke(Native Method)
                                                                                    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:888)
                                                                                    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:778)

我也尝试过代码

    public class BluetoothSendRecv extends BluetoothGattCallback{

        public BluetoothManager mBluetoothManager;
        public BluetoothAdapter mBluetoothAdapter;
        public String mBluetoothDeviceAddress;
        public BluetoothGatt mBluetoothGatt;
        private int mConnectionState = STATE_DISCONNECTED;
        // private final IBinder mBinder = new BluetoothLeService.LocalBinder();
        public Context cntxt;
       .......
UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT);

        // Various callback methods defined by the BLE API.
        public final BluetoothGattCallback mGattCallback =
                new BluetoothGattCallback() {
                    @Override
                    public void onConnectionStateChange(BluetoothGatt gatt, int status,
                                                        int newState) {
                        String intentAction;
                        if (newState == BluetoothProfile.STATE_CONNECTED) {
                            intentAction = ACTION_GATT_CONNECTED;
                            mConnectionState = STATE_CONNECTED;
                            broadcastUpdate(intentAction);
                            Log.i(TAG, "Connected to GATT server.");
                            Log.i(TAG, "Attempting to start service discovery:" +
                                    mBluetoothGatt.discoverServices());

                        } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                            intentAction = ACTION_GATT_DISCONNECTED;
                            mConnectionState = STATE_DISCONNECTED;
                            Log.i(TAG, "Disconnected from GATT server.");
                            broadcastUpdate(intentAction);
                        }
                    }

                    @Override
                    // New services discovered
                    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
                        if (status == BluetoothGatt.GATT_SUCCESS) {
                            //broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
                            for (BluetoothGattService gattService : gatt.getServices()) {
                                Log.i(TAG, "onServicesDiscovered: ---------------------");
                                Log.i(TAG, "onServicesDiscovered: service=" + gattService.getUuid());
                                for (BluetoothGattCharacteristic characteristic : gattService.getCharacteristics()) {
                                    Log.i(TAG, "onServicesDiscovered: characteristic=" + characteristic.getUuid());

                                    if (characteristic.getUuid().toString().equals("0000fee9-0000-1000-8000-00805f9b34fb"/*0000ffe9-0000-1000-8000-00805f9b34fb"*/)) {

                                        Log.w(TAG, "onServicesDiscovered: found LED");

                                        String originalString = "560D0F0600F0AA";

                                        byte[] b = hexStringToByteArray(originalString);

                                        characteristic.setValue(b); // call this BEFORE(!) you 'write' any stuff to the server
                                        mBluetoothGatt.writeCharacteristic(characteristic);
                                        //Toast.makeText(this., "R.string.error_bluetooth_not_supported", Toast.LENGTH_SHORT).show();
                                        //finish()
                                        System.out.println("Writing Mithun");
                                        Toast.makeText(cntxt, originalString, Toast.LENGTH_SHORT).show();
                                        Log.i(TAG, "onServicesDiscovered: , write bytes?! " + byteToHexStr(b));
                                    }
                                }
                            }

                            broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);

                        } else {
                            Log.w(TAG, "onServicesDiscovered received: " + status);
                        }
                    }

                    @Override
                    // Result of a characteristic read operation
                    public void onCharacteristicRead(BluetoothGatt gatt,
                                                     BluetoothGattCharacteristic characteristic,
                                                     int status) {
                        if (status == BluetoothGatt.GATT_SUCCESS) {
                            byte[] data = characteristic.getValue();
                            System.out.println("reading");
                            System.out.println(new String(data));
                            broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
                        }
                    }
                    //...
                };
        private void broadcastUpdate(final String action) {
            final Intent intent = new Intent(action);
            //sendBroadcast(intent);
        }

        .....
    }

Then logcat report  is as follows aaaa

D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=6 device=CC:1E:39:39:62:1C
I/ContentValues: Connected to GATT server.
D/BluetoothGatt: discoverServices() - device: CC:1E:39:39:62:1C
I/ContentValues: Attempting to start service discovery:true
D/BluetoothGatt: onSearchComplete() = Device=CC:1E:39:39:62:1C Status=0
I/ContentValues: onServicesDiscovered: ---------------------
I/ContentValues: onServicesDiscovered: service=00001800-0000-1000-8000-00805f9b34fb
I/ContentValues: onServicesDiscovered: characteristic=00002a00-0000-1000-8000-00805f9b34fb


I think this condition is not fullfilled
if(characteristic.getUuid().toString().equals("0000fee9-0000-1000-8000-00805f9b34fb"/*0000ffe9-0000-1000-8000-00805f9b34fb"*/)) 

最佳答案

我认为你必须在尝试连接之前添加“Scan”方法。这是ble架构的规则。像这样:

 private void startScanning(final boolean enable, BluetoothAdapter mBluetoothAdapter) {
    bluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
    List<ScanFilter> scanFilters = new ArrayList<>();
    final ScanSettings settings = new ScanSettings.Builder().build();
    ScanFilter scanFilter = new ScanFilter.Builder().setServiceUuid(ParcelUuid.fromString(UUID_SERVICE)).build();
    scanFilters.add(scanFilter);
    bluetoothLeScanner.startScan(scanFilters, settings, scanCallback);

}

如果 Ble 设备已建立:

ScanCallback scanCallback = new ScanCallback() {
    @Override
    public void onScanResult(int callbackType, ScanResult result) {
        super.onScanResult(callbackType, result);
        bluetoothDevice = result.getDevice();
        Log.d(TAG, "onScanResult: bluetoothDevice.getAddress());
        mScanning = false;
        String adress = bluetoothDevice.getAddress();
        bluetoothLeScanner.stopScan(scanCallback);
        connect(bluetoothDevice);

    }

关于java - BLE 发送/接收;尝试从空对象引用上的字段 'android.bluetooth.BluetoothGattCallback BluetoothLeService.mGattCallback' 读取,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51046091/

相关文章:

java - 变量需要声明为final

java - MockwebServer 不模拟 http 调用

android - BluetoothGattServer cancelConnection 不取消连接

iOS - 如何在 BLE 外围设备上发现未公布的服务

java - 是否可以有一个类型参数扩展另外 2 个类型参数?

java - 比较两个字段时出错

java - Android Java 登录 Activity 方向更改

android - 设置 Surface View 的大小和位置

Android 应用程序崩溃 - 未知原因

ios - 如何通过 CoreBluetooth 在蓝牙设备上播放声音/音频?