多项活动服务
Posted
技术标签:
【中文标题】多项活动服务【英文标题】:Service for multiple activities 【发布时间】:2016-08-01 08:40:24 【问题描述】:我正在开发一个与蓝牙模块(微芯片的 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 的帮助下编辑了这个问题
【问题讨论】:
在调用bindService
之前让服务启动,更多here,输入^F Binding to a Started Service
我向你推荐了依赖注入,但正如@pslink 提醒我的那样,服务默认是单例的,所以它不能解决你的问题。对不起:(
@pskink 我尝试在调用 bindService 之前启动服务,但结果是一样的
好吧,这可能是因为你在 onUnbind
中调用了 mBluetoothGatt.close();
,在其他地方调用它
无论如何它都不起作用。在我调用的第一个活动中:gattServiceIntent = new Intent(this, BluetoothLeService.class);
startService(gattServiceIntent);
bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
在 onPause() 中我写:super.onPause();
unregisterReceiver(mGattUpdateReceiver);
h.removeCallbacksAndMessages(null);
unbindService(mServiceConnection);
在另一个活动中我只调用 bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
在 onUnBind我删除了 mBluetoothGatt.close();但它在第二个活动中崩溃
【参考方案1】:
android 中有两种类型的服务:Started 和 Bound。您正在使用第二个,Bound。这种类型与启动它的组件的生命周期更相关。
在您的场景中,我建议使用 Started Android 服务并调用:
startService(intent);
在 Activity 的 onCreate()
回调中启动它。最终您也可以将其添加到 Application java 文件中。
更多信息请访问:https://developer.android.com/guide/components/services.html
【讨论】:
第三种是:“started and bound”,看我上面的评论 谢谢你的回答,我同意你最好使用“开始”而不是“绑定”。但是我如何修改我的服务以使其适应“已启动”以上是关于多项活动服务的主要内容,如果未能解决你的问题,请参考以下文章