我试图从gatt服务器读取一个值并在屏幕上显示它。我经历了各种各样的教程,并试图找到各种方法来解决这个问题,但我在某处绊倒了!
我们会感激你的帮助。
布局XML:

<?xml version="1.0" encoding="utf-8"?>

<TextView android:text="Key : " android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/textView2" />

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textAppearance="?android:attr/textAppearanceMedium"
    android:text="Medium Text"
    android:id="@+id/pubkey"
    android:layout_alignTop="@+id/textView2"
    android:layout_toEndOf="@+id/textView2"
    android:layout_marginStart="30dp" />
</RelativeLayout>

main活动.java
public class MainActivity extends Activity implements  BluetoothAdapter.LeScanCallback {
private static final String TAG = "BluetoothGattActivity";
private static final String DEVICE_NAME = "PUNE\u0005\u0012\b";

/*
SECURITY SERVICE
 */
private static final UUID SECURITY_SERVICE = UUID.fromString("3E099914-293F-11E4-93BD-AFD0FE6D1DFD");
private static final UUID SECURITY_PUBLICKEY = UUID.fromString("3E099915-293F-11E4-93BD-AFD0FE6D1DFD");


private BluetoothAdapter mBluetoothAdapter;
private SparseArray<BluetoothDevice> mDevices;

private BluetoothGatt mConnectedGatt;

private  TextView publicKEY;

private ProgressDialog mProgress;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
    setContentView(R.layout.activity_main);
    setProgressBarIndeterminate(true);

    publicKEY = (TextView) findViewById(R.id.pubkey);


    BluetoothManager manager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
    mBluetoothAdapter = manager.getAdapter();

    mDevices = new SparseArray<BluetoothDevice>();

    mProgress = new ProgressDialog(this);
    mProgress.setIndeterminate(true);
    mProgress.setCancelable(false);

}

@Override
protected void onResume() {
    super.onResume();
    /*
     * We need to enforce that Bluetooth is first enabled, and take the
     * user to settings to enable it if they have not done so.
     */
    if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
        //Bluetooth is disabled
        Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivity(enableBtIntent);
        finish();
        return;
    }

    /*
     * Check for Bluetooth LE Support.  In production, our manifest entry will keep this
     * from installing on these devices, but this will allow test devices or other
     * sideloads to report whether or not the feature exists.
     */
    if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
        Toast.makeText(this, "No LE Support.", Toast.LENGTH_SHORT).show();
        finish();
        return;
    }

    clearDisplayValues();
}


@Override
protected void onPause() {
    super.onPause();
    //Make sure dialog is hidden
    mProgress.dismiss();
    //Cancel any scans in progress
    mHandler.removeCallbacks(mStopRunnable);
    mHandler.removeCallbacks(mStartRunnable);
    mBluetoothAdapter.stopLeScan(this);
}

@Override
protected void onStop() {
    super.onStop();
    //Disconnect from any active tag connection
    if (mConnectedGatt != null) {
        mConnectedGatt.disconnect();
        mConnectedGatt = null;
    }
}


@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Add the "scan" option to the menu
    getMenuInflater().inflate(R.menu.main, menu);
    //Add any device elements we've discovered to the overflow menu
    for (int i=0; i < mDevices.size(); i++) {
        BluetoothDevice device = mDevices.valueAt(i);
        menu.add(0, mDevices.keyAt(i), 0, device.getName());
    }

    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.action_scan:
            mDevices.clear();
            startScan();
            return true;
        default:
            //Obtain the discovered device to connect with
            BluetoothDevice device = mDevices.get(item.getItemId());
            Log.i(TAG, "Connecting to "+device.getName());
            /*
             * Make a connection with the device using the special LE-specific
             * connectGatt() method, passing in a callback for GATT events
             */
            mConnectedGatt = device.connectGatt(this, false, mGattCallback);
            //Display progress UI
            mHandler.sendMessage(Message.obtain(null, MSG_PROGRESS, "Connecting to "+device.getName()+"..."));
            return super.onOptionsItemSelected(item);
    }
}

private void clearDisplayValues() {
    publicKEY.setText("---");

}

private Runnable mStopRunnable = new Runnable() {
    @Override
    public void run() {
        stopScan();
    }
};
private Runnable mStartRunnable = new Runnable() {
    @Override
    public void run() {
        startScan();
    }
};

private void startScan() {
    mBluetoothAdapter.startLeScan(this);
    setProgressBarIndeterminateVisibility(true);

    mHandler.postDelayed(mStopRunnable, 2500);
}

private void stopScan() {
    mBluetoothAdapter.stopLeScan(this);
    setProgressBarIndeterminateVisibility(false);
}

我所有的回音都在这里
/* BluetoothAdapter.LeScanCallback */


@Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
    Log.i(TAG, "New LE Device: " + device.getName() + " @ " + rssi);
    /*
     * We are looking for SensorTag devices only, so validate the name
     * that each device reports before adding it to our collection
     */
    if (DEVICE_NAME.equals(device.getName())) {
        mDevices.put(device.hashCode(), device);
        //Update the overflow menu
        invalidateOptionsMenu();
    }

}

private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {


    private int mState = 0;

    private void reset()
    {
     mState= 0;
    }

    private void advance()
    {
        mState++;
    }

    private void enabled(BluetoothGatt gatt) {
        BluetoothGattCharacteristic characteristic;

        switch(mState) {
            case 0:
                Log.d(TAG, "Enable Public Key");
                characteristic = gatt.getService(SECURITY_SERVICE).getCharacteristic(SECURITY_PUBLICKEY);

                break;

            default:
                mHandler.sendEmptyMessage(MSG_DISMISS);
                Log.i(TAG, "All Sensors Enabled");
                return;
        }


    }

    private void readData(BluetoothGatt gatt)
    {

        BluetoothGattCharacteristic characteristic;

        switch (mState) {
            case 0:
                Log.d(TAG, "Reading Public Key");
                characteristic = gatt.getService(SECURITY_SERVICE).getCharacteristic(SECURITY_PUBLICKEY);
                break;

            default:
                mHandler.sendEmptyMessage(MSG_DISMISS);
                Log.i(TAG, "All Sensors Enabled");
                return;
        }
        gatt.readCharacteristic(characteristic);


    }

    private void enableNotif(BluetoothGatt gatt) {
        BluetoothGattCharacteristic characteristic;
        switch (mState) {
            case 0:
                Log.d(TAG, "Setting Notification Public Key");
                characteristic = gatt.getService(SECURITY_SERVICE).getCharacteristic(SECURITY_PUBLICKEY);
                break;

            default:
                mHandler.sendEmptyMessage(MSG_DISMISS);
                Log.i(TAG, "All Sensors Enabled");
                return;
        }

        gatt.setCharacteristicNotification(characteristic, true);

    }

    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
        Log.d(TAG, "Connection State Change: " + status + " -> " + connectionState(newState));
        if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) {
            /*
             * Once successfully connected, we must next discover all the services on the
             * device before we can read and write their characteristics.
             */
            gatt.discoverServices();
            mHandler.sendMessage(Message.obtain(null, MSG_PROGRESS, "Discovering Services..."));
        } else if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_DISCONNECTED) {
            /*
             * If at any point we disconnect, send a message to clear the weather values
             * out of the UI
             */
            mHandler.sendEmptyMessage(MSG_CLEAR);
        } else if (status != BluetoothGatt.GATT_SUCCESS) {
            /*
             * If there is a failure at any stage, simply disconnect
             */
            gatt.disconnect();
        }
    }

    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
        Log.d(TAG, "Services Discovered: " + status);
        mHandler.sendMessage(Message.obtain(null, MSG_PROGRESS, "Enabling Public Key..."));

        reset();
        enabled(gatt);

    }

    @Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic,int status ) {
        if(SECURITY_PUBLICKEY.equals(characteristic.getUuid())) {
            mHandler.sendMessage(Message.obtain(null,MSG_PUBLICKEY,characteristic));
        }
        enableNotif(gatt);
        readData(gatt);

    }


    @Override
    public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        //After writing the enable flag, next we read the initial value
        readData(gatt);
    }

    @Override
    public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
        Log.d(TAG, "Remote RSSI: " + rssi);
    }

    private String connectionState(int status) {
        switch (status) {
            case BluetoothProfile.STATE_CONNECTED:
                return "Connected";
            case BluetoothProfile.STATE_DISCONNECTED:
                return "Disconnected";
            case BluetoothProfile.STATE_CONNECTING:
                return "Connecting";
            case BluetoothProfile.STATE_DISCONNECTING:
                return "Disconnecting";
            default:
                return String.valueOf(status);
        }
    }

};



private static final int MSG_PROGRESS = 201;
private static final int MSG_DISMISS = 202;
private static final int MSG_CLEAR = 301;
private static final int MSG_PUBLICKEY = 101;

private Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        BluetoothGattCharacteristic characteristic;
        switch (msg.what) {
            case MSG_PUBLICKEY:
                characteristic = (BluetoothGattCharacteristic) msg.obj;
                if (characteristic.getValue() == null) {
                    Log.w(TAG, "Error obtaining humidity value");
                    return;
                }
                updatePubKey(characteristic);
                break;

            case MSG_PROGRESS:
                mProgress.setMessage((String) msg.obj);
                if (!mProgress.isShowing()) {
                    mProgress.show();
                }
                break;
            case MSG_DISMISS:
                mProgress.hide();
                break;
            case MSG_CLEAR:
                clearDisplayValues();
                break;
        }
    }
};

private void updatePubKey(BluetoothGattCharacteristic characteristic) {

    byte[] data = characteristic.getValue();
    final StringBuilder stringBuilder = new StringBuilder(data.length);
    for(byte byteChar : data)
        stringBuilder.append(String.format("%02X ", byteChar));
    publicKEY.setText(new String(data)+" "+stringBuilder.toString());

}


}

这是日志
Timeline: Timeline: Activity_idle id: android.os.BinderProxy@41cc5460         time:10882957
BluetoothAdapter: startLeScan(): null
BluetoothAdapter: onClientRegistered() - status=0 clientIf=5
BluetoothGattActivity: New LE Device: null @ -83
BluetoothAdapter: stopLeScan()
BluetoothAdapter: startLeScan(): null
BluetoothAdapter: onClientRegistered() - status=0 clientIf=5
BluetoothGattActivity: New LE Device: PUNE @ -38
BluetoothAdapter: stopLeScan()
BluetoothGattActivity: Connecting to PUNE
BluetoothGatt: connect() - device: B0:B4:48:BA:40:84, auto: false
BluetoothGatt: registerApp()
BluetoothGatt: registerApp() - UUID=0bdf35a7-d4d0-4048-be15-a6cb030626f5
BluetoothGatt: onClientRegistered() - status=0 clientIf=5
BluetoothGatt: onClientConnectionState() - status=0 clientIf=5                device=B0:B4:48:BA:40:84
BluetoothGattActivity: Connection State Change: 0 -> Connected
BluetoothGatt: discoverServices() - device: B0:B4:48:BA:40:84

我要找的服务都在这里。
onGetCharacteristic() - Device=B0:B4:48:BA:40:84 UUID=3e099919-293f-11e4-93bd-afd0fe6d1dfd
onGetCharacteristic() - Device=B0:B4:48:BA:40:84 UUID=3e099915-293f-11e4-93bd-afd0fe6d1dfd
onGetCharacteristic() - Device=B0:B4:48:BA:40:84 UUID=3e099916-293f-11e4-93bd-afd0fe6d1dfd
onGetCharacteristic() - Device=B0:B4:48:BA:40:84 UUID=3e099917-293f-11e4-93bd-afd0fe6d1dfd

问题就出在这里。
 D/BluetoothGattActivity: Services Discovered: 0
 D/BluetoothGattActivity: Enable Public Key
 W/BluetoothGatt: Unhandled exception in callback
 W/BluetoothGatt: java.lang.NullPointerException
 W/BluetoothGatt:     at gune.blegune.MainActivity$3.enabled(MainActivity.java:232)
 W/BluetoothGatt:     at gune.blegune.MainActivity$3.onServicesDiscovered(MainActivity.java:314)
 W/BluetoothGatt:     at android.bluetooth.BluetoothGatt$1.onSearchComplete(BluetoothGatt.java:295)
 W/BluetoothGatt:     at android.bluetooth.IBluetoothGattCallback$Stub.onTransact(IBluetoothGattCallback.java:215)
 W/BluetoothGatt:     at android.os.Binder.execTransact(Binder.java:404)
 W/BluetoothGatt:     at dalvik.system.NativeStart.run(Native Method)
 D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=5 device=B0:B4:48:BA:40:84
 D/BluetoothGattActivity: Connection State Change: 0 -> Disconnected
 D/BluetoothAdapter: stopLeScan()

拜托。我们将非常感谢您的帮助。多谢!

最佳答案

我想这是一条线,它正在抛出npe:
characteristic=gatt.getservice(安全服务).getcharacteristic(安全公钥);
所以要么
关贸总协定无效或
gatt.getservice(安全服务)
正在返回空值。
你能加些日志来找出是哪一个吗?
我猜这是第二种情况,在这种情况下,我建议您对BluetoothGatt对象调用getServices(),并在结果列表中记录每个BluetoothGattService对象的UUID,以再次检查您是否拥有您认为应该拥有的服务UUID。
getservice的规范中写着“bluetoothgattservice(如果支持),或者如果远程设备没有提供所请求的服务,则为空。”

09-27 05:57