为多项活动提供服务

时间:2016-08-01 08:40:24

标签: android android-activity bluetooth bluetooth-lowenergy gatt

我正在开发一个与蓝牙模块(微芯片的RN4020)通信的应用程序。此应用程序使用一种服务来处理与模块的通信(连接/读/写)。当我使用一个活动时,没有任何问题。当我使用2个活动时出现问题。当我向模块发送数据时,手机会与模块断开连接并崩溃。 我认为问题是服务,根据我的说法,它不会在第二个活动中绑定。我该如何解决?

这是服务:

public class BluetoothLeService extends Service {

private final static String TAG = BluetoothLeService.class.getSimpleName();         //Get name of service to tag debug and warning messages
private BluetoothManager mBluetoothManager;                                         //BluetoothManager used to get the BluetoothAdapter
private BluetoothAdapter mBluetoothAdapter;                                         //The BluetoothAdapter controls the BLE radio in the phone/tablet
private BluetoothGatt mBluetoothGatt;                                               //BluetoothGatt controls the Bluetooth communication link
private String mBluetoothDeviceAddress;                                             //Address of the connected BLE device

public final static String ACTION_GATT_CONNECTED = "com.example.app.ACTION_GATT_CONNECTED"; //Strings representing actions to broadcast to activities
public final static String ACTION_GATT_DISCONNECTED = "com.example.app.ACTION_GATT_DISCONNECTED";
public final static String ACTION_GATT_SERVICES_DISCOVERED = "com.example.app.ACTION_GATT_SERVICES_DISCOVERED";
public final static String ACTION_DATA_AVAILABLE = "com.example.app.ACTION_DATA_AVAILABLE";
public final static String ACTION_DATA_WRITTEN = "com.example.app.ACTION_DATA_WRITTEN";
public final static String EXTRA_DATA = "com.example.app.EXTRA_DATA";

public final static UUID UUID_MLDP_DATA_PRIVATE_CHARACTERISTIC = UUID.fromString(WorkActivity.MLDP_DATA_PRIVATE_CHAR);
public final static UUID UUID_CHARACTERISTIC_NOTIFICATION_CONFIG = UUID.fromString(WorkActivity.CHARACTERISTIC_NOTIFICATION_CONFIG);

private final IBinder mBinder = new LocalBinder();                                  //Binder for Activity that binds to this Service

// ----------------------------------------------------------------------------------------------------------------
// An activity has bound to this service
@Override
public IBinder onBind(Intent intent) {
    return mBinder;                                                                 //Return LocalBinder when an Activity binds to this Service
}

// ----------------------------------------------------------------------------------------------------------------
// An activity has unbound from this service 
@Override
public boolean onUnbind(Intent intent) {
    /*if (mBluetoothGatt != null) {                                                   //Check for existing BluetoothGatt connection
        mBluetoothGatt.close();                                                     //Close BluetoothGatt coonection for proper cleanup
        mBluetoothGatt = null;                                                      //No longer have a BluetoothGatt connection
    }*/
    return super.onUnbind(intent);

}

// ----------------------------------------------------------------------------------------------------------------
// A Binder to return to an activity to let it bind to this service 
public class LocalBinder extends Binder {
    BluetoothLeService getService() {
        return BluetoothLeService.this;                                             //Return this instance of BluetoothLeService so clients can call its public methods
    }
}

// ----------------------------------------------------------------------------------------------------------------
// Implements callback methods for GATT events that the app cares about.  For example: connection change and services discovered.
// When onConnectionStateChange() is called with newState = STATE_CONNECTED then it calls mBluetoothGatt.discoverServices()
// resulting in another callback to onServicesDiscovered()
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { //Change in connection state
        if (newState == BluetoothProfile.STATE_CONNECTED) {                         //See if we are connected
            broadcastUpdate(ACTION_GATT_CONNECTED);                                 //Go broadcast an intent to say we are connected
            Log.i(TAG, "Connected to GATT server, starting service discovery");
            mBluetoothGatt.discoverServices();                                      //Discover services on connected BLE device
        } 
        else if (newState == BluetoothProfile.STATE_DISCONNECTED) {                 //See if we are not connected
            broadcastUpdate(ACTION_GATT_DISCONNECTED);                              //Go broadcast an intent to say we are disconnected
            Log.i(TAG, "Disconnected from GATT server.");
        }
    }

    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {              //BLE service discovery complete
        if (status == BluetoothGatt.GATT_SUCCESS) {                                 //See if the service discovery was successful
            broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);                       //Go broadcast an intent to say we have discovered services
        } 
        else {                                                                      //Service discovery failed so log a warning
            Log.w(TAG, "onServicesDiscovered received: " + status);
        }
    }

    //For information only. This application uses Indication to receive updated characteristic data, not Read
    @Override
    public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { //A request to Read has completed
        if (status == BluetoothGatt.GATT_SUCCESS) {                                 //See if the read was successful
            broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);                 //Go broadcast an intent with the characteristic data
        }
    }

    //For information only. This application sends small packets infrequently and does not need to know what the previous write completed
    @Override
    public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { //A request to Write has completed
        if (status == BluetoothGatt.GATT_SUCCESS) {                                 //See if the write was successful
            broadcastUpdate(ACTION_DATA_WRITTEN, characteristic);                   //Go broadcast an intent to say we have have written data
        }
    }

    @Override
    public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { //Indication or notification was received
        broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);                     //Go broadcast an intent with the characteristic data
    }
};

// ----------------------------------------------------------------------------------------------------------------
// Broadcast an intent with a string representing an action
private void broadcastUpdate(final String action) {
    final Intent intent = new Intent(action);                                       //Create new intent to broadcast the action
    sendBroadcast(intent);                                                          //Broadcast the intent
}

// ----------------------------------------------------------------------------------------------------------------
// Broadcast an intent with a string representing an action an extra string with the data
// Modify this code for data that is not in a string format 
private void broadcastUpdate(final String action, final BluetoothGattCharacteristic characteristic) {
    final Intent intent = new Intent(action);                                       //Create new intent to broadcast the action
    if(action.equals(ACTION_DATA_AVAILABLE)) {                                      //See if we need to send data
        if (UUID_MLDP_DATA_PRIVATE_CHARACTERISTIC.equals(characteristic.getUuid())) { //See if this is the correct characteristic 
            String dataValue = characteristic.getStringValue(0);                    //Get the data (in this case it is a string)
            intent.putExtra(EXTRA_DATA, dataValue);                                 //Add the data string to the intent
        }
    }
    else {                                                                          //Did not get an action string we expect 
        Log.d(TAG, "Action: " + action);
    }
    sendBroadcast(intent);                                                          //Broadcast the intent
}

// ----------------------------------------------------------------------------------------------------------------
// Initialize by getting the BluetoothManager and BluetoothAdapter 
public boolean initialize() {
    if (mBluetoothManager == null) {                                                //See if we do not already have the BluetoothManager
        mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); //Get the BluetoothManager
        if (mBluetoothManager == null) {                                            //See if we failed
            Log.e(TAG, "Unable to initialize BluetoothManager.");
            return false;                                                           //Report the error
        }
    }

    mBluetoothAdapter = mBluetoothManager.getAdapter();                             //Ask the BluetoothManager to get the BluetoothAdapter
    if (mBluetoothAdapter == null) {                                                //See if we failed
        Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
        return false;                                                               //Report the error
    }

    return true;                                                                    //Success, we have a BluetoothAdapter to control the radio
}

// ----------------------------------------------------------------------------------------------------------------
// Open a BluetoothGatt connection to a BLE device given its address
public boolean connect(final String address) {
    if (mBluetoothAdapter == null || address == null) {                             //Check that we have a Bluetooth adappter and device address
        Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");     //Log a warning that something went wrong
        return false;                                                               //Failed to connect
    }

    // Previously connected device.  Try to reconnect.
    if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress) && mBluetoothGatt != null) { //See if there was previous connection to the device
        Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
        if (mBluetoothGatt.connect()) {                                             //See if we can connect with the existing BluetoothGatt to connect
            return true;                                                            //Success
        } 
        else {
            return false;                                                           //Were not able to connect
        }
    }

    final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);      //No previous device so get the Bluetooth device by referencing its address
    if (device == null) {                                                           //Check whether a device was returned
        Log.w(TAG, "Device not found.  Unable to connect.");                        //Warn that something went wrong
        return false;                                                               //Failed to find the device
    }

    mBluetoothGatt = device.connectGatt(this, false, mGattCallback);                //Directly connect to the device so autoConnect is false
    Log.d(TAG, "Trying to create a new connection.");
    mBluetoothDeviceAddress = address;                                              //Record the address in case we bneed to reconnect with the existing BluetoothGatt
    return true;
}

// ----------------------------------------------------------------------------------------------------------------
// Retrieve and return a list of supported GATT services on the connected device
public List<BluetoothGattService> getSupportedGattServices() {
    if (mBluetoothGatt == null) {                                                   //Check that we have a valid GATT connection
        return null;
    }
    return mBluetoothGatt.getServices();                                            //Get the list of services
}

// ----------------------------------------------------------------------------------------------------------------
// Disconnects an existing connection or cancel a pending connection
// BluetoothGattCallback.onConnectionStateChange() will get the result
public void disconnect() {
    if (mBluetoothAdapter == null || mBluetoothGatt == null) {                      //Check that we have a GATT connection to disconnect
        Log.w(TAG, "BluetoothAdapter not initialized");
        return;
    }
    mBluetoothGatt.disconnect();                                                    //Disconnect GATT connection
}

// ----------------------------------------------------------------------------------------------------------------
// Request a read of a given BluetoothGattCharacteristic. The Read result is reported asynchronously through the
// BluetoothGattCallback onCharacteristicRead callback method.
// For information only. This application uses Indication to receive updated characteristic data, not Read
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
    if (mBluetoothAdapter == null || mBluetoothGatt == null) {                      //Check that we have access to a Bluetooth radio
        Log.w(TAG, "BluetoothAdapter not initialized");
        return;
    }
    mBluetoothGatt.readCharacteristic(characteristic);                              //Request the BluetoothGatt to Read the characteristic
}

// ----------------------------------------------------------------------------------------------------------------
// Write to a given characteristic. The completion of the write is reported asynchronously through the
// BluetoothGattCallback onCharacteristicWrire callback method.
public void writeCharacteristic(BluetoothGattCharacteristic characteristic) {
    if (mBluetoothAdapter == null || mBluetoothGatt == null) {                      //Check that we have access to a Bluetooth radio
        Log.w(TAG, "BluetoothAdapter not initialized");
        return;
    }
    int test = characteristic.getProperties();                                      //Get the properties of the characteristic
    if ((test & BluetoothGattCharacteristic.PROPERTY_WRITE) == 0 && (test & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) == 0) { //Check that the property is writable 
        return;
    }

    if (mBluetoothGatt.writeCharacteristic(characteristic)) {                       //Request the BluetoothGatt to do the Write
        Log.d(TAG, "writeCharacteristic successful");                               //The request was accepted, this does not mean the write completed
    } 
    else {
        Log.d(TAG, "writeCharacteristic failed");                                   //Write request was not accepted by the BluetoothGatt
    }
}

// ----------------------------------------------------------------------------------------------------------------
// Enable notification on a characteristic
// For information only. This application uses Indication, not Notification
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {
    if (mBluetoothAdapter == null || mBluetoothGatt == null) {                      //Check that we have a GATT connection
        Log.w(TAG, "BluetoothAdapter not initialized");
        return;
    }
    mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);          //Enable notification and indication for the characteristic
//        if (UUID_MLDP_DATA_PRIVATE_CHARACTERISTIC.equals(characteristic.getUuid())) { 
    BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID_CHARACTERISTIC_NOTIFICATION_CONFIG); //Get the descripter that enables notification on the server
    descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);         //Set the value of the descriptor to enable notification
    mBluetoothGatt.writeDescriptor(descriptor);                                     //Write the descriptor
//        }
}

// ----------------------------------------------------------------------------------------------------------------
// Enable indication on a characteristic
public void setCharacteristicIndication(BluetoothGattCharacteristic characteristic, boolean enabled) {
    if (mBluetoothAdapter == null || mBluetoothGatt == null) {                      //Check that we have a GATT connection
        Log.w(TAG, "BluetoothAdapter not initialized");
        return;
    }
    mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);          //Enable notification and indication for the characteristic

    // This is specific to our custom profile
//        if (UUID_MLDP_DATA_PRIVATE_CHARACTERISTIC.equals(characteristic.getUuid())) {
    BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID_CHARACTERISTIC_NOTIFICATION_CONFIG); //Get the descripter that enables indication on the server
    descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);           //Set the value of the descriptor to enable indication
    mBluetoothGatt.writeDescriptor(descriptor);                                     //Write the descriptor
//        }
}

}

在onCreate()的第一个活动中,我打电话:

Intent gattServiceIntent = new Intent(this, BluetoothLeService.class);
startService(gattServiceIntent);
bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);

在onPause()中:

super.onPause();
unregisterReceiver(mGattUpdateReceiver);
unbindService(mServiceConnection);
mBluetoothLeService = null;

在onCreate()的第二个活动中,我打电话:

Intent gattServiceIntent = new Intent(this, BluetoothLeService.class);
bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);

提前谢谢你,抱歉我的英文不好

我在@pskink

的帮助下编辑了这个问题

1 个答案:

答案 0 :(得分:0)

Android中有两种类型的服务:已启动已绑定。你正在使用第二个,Bound。此类型与启动它的组件的生命周期更相关。

在您的方案中,我建议使用已启动的Android服务并致电:

startService(intent);

在您的活动的onCreate()回调中启动它。最后,您也可以将它添加到Application java文件中。

更多信息:https://developer.android.com/guide/components/services.html