我正在开发一个与蓝牙模块(微芯片的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
的帮助下编辑了这个问题答案 0 :(得分:0)
Android中有两种类型的服务:已启动和已绑定。你正在使用第二个,Bound。此类型与启动它的组件的生命周期更相关。
在您的方案中,我建议使用已启动的Android服务并致电:
startService(intent);
在您的活动的onCreate()
回调中启动它。最后,您也可以将它添加到Application java文件中。
更多信息:https://developer.android.com/guide/components/services.html