web-dev-qa-db-fra.com

Android BluetoothGatt - état 133 - enregistrer le rappel

Tout d'abord, j'ai lu RESOLU: le rappel GATT ne parvient pas à s'enregistrer et j'ai pris les mesures suggérées dans ce message pour résoudre ce problème sans succès. Si vous ne l'avez pas lu, le correctif recommandé consiste à effectuer tous les appels BLE à partir du thread principal directement ou avec un gestionnaire.

Je travaille sur une application BLE qui souhaite exécuter un service (appelé depuis l'activité une fois toutes les 10 secondes) qui effectue ces tâches:

1)Gets list of our products available to connect to (done, works)

2)For each available device:

          2a)connect to device
          2b)discover services
          2c)read 5 characteristics in this fashion:
             2c1)read characteristic
             2c2)onCharacteristicRead parse data
             2c3)when finished with data read next characteristic
             2c4)repeat until all are read (this is done using a state var and switch statement)
         2d)disconnect from device
         2e)connect to next device
         2f)repeat until all devices are read from
         2g)stopSelf()

Donc le problème ... Tout fonctionne très bien pendant un petit moment. Je peux effectuer le démarrage complet du service {startService (...); dans mainActivity} pour terminer {stopSelf (); en service} 6 fois.

La 7ème fois, je reçois BluetoothGatt Impossible d'enregistrer le rappel. Je ne sais pas pourquoi je peux l'exécuter 6 fois avec succès, puis échouer la 7e fois.

Gardez à l'esprit que je fais tous les appels BLE à partir du thread principal, et cela a été confirmé dans le journal de chat à partir de plusieurs emplacements.

Voici un aperçu de mon code:

SERVICE.Java

private Handler handler = new Handler();
private BluetoothGatt cGatt = null;
private int unitIndex = 0; // keep track of currently connected unit
private int state = 0; //used to keep track of which characteristic to read next

public int onStartCommand(Intent intent, int flags, int startId) 
{
    Log.i(TAG, "Service Started...");
    //get ArrayList of units

    if(units.size > 0)
        handler.post(connectNextRunnable); //calls connectNextDevice()
    else
        stopSelf();   
}

private Runnable discoverServices = new Runnable()
{
    public void run()
    {
        cGatt.discoverServices();
    }
}

private Runnable readNextValue = new Runnable()
{
    public void run()
    {
        BluetoothGattCharacteristic c = null;
        switch(state)
        {
            //set c to appropriate characteristic
        default: // all characteristics read
            unitIndex++;
            handler.post(connectNextRunnable)
            return
        }

        cGatt.readCharacteristic(c);
    }
}

private void connectNextDevice()
{
    if(unitIndex == 0)
        store System.nanoTime in variable

    if(unitIndex >= units.size) //finished will all units
        stopSelf();

    if(unitIndex < units.size)
        cGatt.disconnect //if null
        cGatt.connectGatt(this, false, gattCallback)
}

private BluetoothGattCallback gattCallback = new BluetoothGattCallback() 
{
    public void onConnectionStateChange() 
    {
        handler.post(discoverServices);
    }

    public void onServicesDeiscovered() 
    {
        handler.post(readNextValue);
    }

    public void onCharacteristicRead() 
    {
        ParseData();
    }

    private void ParseData()
    {
        //do stuff with data
        handler.post(readNextValue);
    }
}

Ainsi, comme je l'ai dit, toutes les choses BLE sont appelées à partir du thread principal via un gestionnaire. Le service s'exécute avec succès 6 fois du début à la fin. La 7ème fois, je reçois ce stupide n'a pas réussi à enregistrer le rappel.

Je peux fournir plus d'informations logcat si vous pensez que cela est pertinent. Je ne l'ai pas dans le message d'origine car je lui envoie beaucoup d'informations pour vérifier les données reçues, etc.

Les informations ci-dessous sont les informations logcat pour la 7ème exécution de mon service du début à la fin.

08-15 12:00:10.746: I/PMIQ BTS(32027): Service Started...
08-15 12:00:10.746: I/PMIQ BTS(32027): Units: 1
08-15 12:00:10.746: D/AbsListView(32027): unregisterIRListener() is called 
08-15 12:00:10.766: I/PMIQ BTS(32027): Connecting to next device...
08-15 12:00:10.766: I/PMIQ BTS(32027): Unit index = 0
08-15 12:00:10.766: I/PMIQ BTS(32027): Connecting to pmIQ-IQ130_D93A
08-15 12:00:10.766: I/System.out(32027): main
08-15 12:00:10.766: D/BluetoothGatt(32027): connect() - device: 00:1E:C0:19:D9:3A, auto: false
08-15 12:00:10.766: D/BluetoothGatt(32027): registerApp()
08-15 12:00:10.766: D/BluetoothGatt(32027): registerApp() - UUID=e9d10870-4b09-451c-a9fa-c6b5f3594a77
08-15 12:00:10.766: I/BluetoothGatt(32027): Client registered, waiting for callback
08-15 12:00:10.766: D/BluetoothGatt(32027): onClientRegistered() - status=133 clientIf=0
08-15 12:00:10.766: I/PMIQ BTS(32027): CONECTION STATE CHANGED...Binder_2
**08-15 12:00:10.766: E/BluetoothGatt(32027): Failed to register callback**
08-15 12:00:10.766: I/PMIQ BTS(32027): Could not connect to null ... 257
08-15 12:00:10.766: I/PMIQ BTS(32027): Connecting to next device...
08-15 12:00:10.766: I/PMIQ BTS(32027): Unit index = 1
08-15 12:00:10.766: I/PMIQ BTS(32027): ******************************
08-15 12:00:10.766: I/PMIQ BTS(32027): Start Time: 4360642409647
08-15 12:00:10.766: I/PMIQ BTS(32027): End Time: 4360648970925
08-15 12:00:10.766: I/PMIQ BTS(32027): Difference: 6561278
08-15 12:00:10.766: I/PMIQ BTS(32027): Time to complete: 6
08-15 12:00:10.766: I/PMIQ BTS(32027): ******************************
08-15 12:00:10.876: I/PMIQ BTS(32027): ...Service Destroyed

Si vous l'avez fait ici, merci! Je n'ai pu trouver AUCUNE information sur quel statut = 133 signifie?! Cela se produit uniquement lorsque le rappel échoue. Toutes les deux fois, c'est status = 0.

08-15 12:00:10.766: D/BluetoothGatt(32027): onClientRegistered() - status=133 clientIf=0

Si quelqu'un pouvait même répondre à cela .. cela pourrait m'aider grandement. Ou si quelqu'un peut me dire pourquoi il ne fonctionne que 6 fois. Toute idée ou intuition pourrait être utile!

Merci tout le monde!

37
ck1221

D'accord, je l'ai compris. Le problème était principalement une erreur de lecture de la documentation BluetoothGatt. J'appelais .disconnect(), mais pas .close(). Étant donné que le Galaxy s4 ne peut gérer que 6 connexions à la fois, mon service ne fonctionnait que 6 fois. L'ajout de la .close() à mon code lui a permis de fermer correctement la connexion et de libérer les connexions utilisées.

Source qui m'a fait relire les documents plus attentivement!

Pensez donc à utiliser .close () sur votre objet BluetoothGatt si vous avez une connexion récurrente avec les mêmes appareils !!

55
ck1221

Après des mois de recherche et d'arrachage de cheveux, j'ai trouvé une solution dont on ne parle pas normalement.

Votre demande de connexion normale ressemble à ceci:

cGatt.connectGatt(this, false, gattCallback);

Il existe une autre version de la commande connectGatt, avec un 4ème paramètre. Ce paramètre spécifie le type de périphérique Bluetooth auquel vous vous connectez. J'ai ajouté un "2" pour spécifier que je me connecte via Bluetooth LE. (ça s'appelle "transport", pardonnez-moi si mon explication est incorrecte, mais elle a résolu tous mes problèmes)

Essaye ça:

cGatt.connectGatt(this, false, gattCallback, 2);

Et BAM, maintenant mon cauchemar # 133 est terminé (je prie)!

13
btmcmahan

Android OS <6.0:

mBluetoothDevice.connectGatt(context, false, callback);

Système d'exploitation Android> = 6,0:

mBluetoothDevice.connectGatt(context, false, callback, BluetoothDevice.TRANSPORT_LE);

En fin de compte, un équipement matériel est nécessaire pour résoudre complètement ce problème.

4
郑松岚
  • Sur certains appareils, il a été corrigé avec mBluetoothDevice.connectGatt(context, false, callback, BluetoothDevice.TRANSPORT_LE);

  • sur certains appareils comme Samsung S7, A8, c'était un problème avec ScanSettings.Builder (). setReportDelay (400) // ou 500 ms. il ne doit pas être égal à 0 ou supérieur à 1000 ms. ScanSettings settings = new ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_BALANCED) .setReportDelay(400) .build();

0
user1278366

Essayez d'utiliser la solution de contournement suivante:

private static boolean gatt_status_133 = false;

final Handler handler = new Handler();

public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {

    if (newState == BluetoothProfile.STATE_CONNECTED) {
        mConnectionState = STATE_CONNECTED;
        Log.i(TAG, "Connected to GATT server.");
        // Attempts to discover services after successful connection.
        Log.i(TAG, "Attempting to start service discovery:" +
                mBluetoothGatt.discoverServices());

    } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
        if(status == 133)
        {
            gatt_status_133=true;
        }
        else{
            mConnectionState = STATE_DISCONNECTED;
            Log.i(TAG, "Disconnected from GATT server."); 
        }
    }
}


@RequiresApi(api = Build.VERSION_CODES.M)
public boolean connect(final String address) {
    if (mBluetoothAdapter == null || address == null) {
        Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
        return false;
    }

    // Previously connected device.  Try to reconnect.
    if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress)
            && mBluetoothGatt != null) {
        Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
        if (mBluetoothGatt.connect()) {
            mConnectionState = STATE_CONNECTING;
            return true;
        } else {
            return false;
        }
    }

    final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
    if (device == null) {
        Log.w(TAG, "Device not found.  Unable to connect.");
        return false;
    }

    mBluetoothGatt= device.connectGatt(this, false, mGattCallback, BluetoothDevice.TRANSPORT_LE);
    Log.d(TAG, "Trying to create a new connection.");
    mBluetoothDeviceAddress = address;
    mConnectionState = STATE_CONNECTING;

    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            if(gatt_status_133)
            {
                Log.d(TAG, "Catch issue");
                connect(address);
                gatt_status_133=false;
            }
        }
    }, 4000);

    return true;
}
0
Artem Kabakov