多项活动服务

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 中有两种类型的服务:StartedBound。您正在使用第二个,Bound。这种类型与启动它的组件的生命周期更相关。

在您的场景中,我建议使用 Started Android 服务并调用:

startService(intent);

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

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

【讨论】:

第三种是:“started and bound”,看我上面的评论 谢谢你的回答,我同意你最好使用“开始”而不是“绑定”。但是我如何修改我的服务以使其适应“已启动”

以上是关于多项活动服务的主要内容,如果未能解决你的问题,请参考以下文章

如何将数据从一项活动传递到多项活动?

多项活动中的暗模式

如何在多项活动中正确使用 Google Plus 登录?

在一个 Sonos 音乐合作伙伴帐户下发布多项服务

阿里云服务器学生9块

Android:使用 ChromeCast 发件人进行多项活动