首页 > 解决方案 > 具有读取 BLE 特性的定时器

问题描述

我正在构建一个 Android 服务。该服务应该连接 BLE 设备并下载它存储在您的内存中的所有信息。

现在我希望这个服务可以在后台运行。这是我的 BlePowerService 扩展服务

public class BlePowerService extends Service {
    public DbLayer db;
    Setting settingApp;
    List<ScanFilter> filters;
    String[] stringSequence = new String[] {CHARACTERISTIC_FORZA_STRING, CHARACTERISTIC_TEMPERATURA_STRING};
    BluetoothAdapter mBluetoothAdapter;
    BluetoothGatt mGatt;
    BluetoothDevice currDevice;
    static final long SCAN_PERIOD = 500;
    static String SPLIT_CHAR =";";
    BluetoothLeScanner mLEScanner;
    Handler mHandler;
    int ReadQueueIndex;
    List<BluetoothGattCharacteristic> ReadQueue;
    BluetoothGattCharacteristic caratteristicaDaLeggere;
    ScanSettings settings;
    Integer ultimaForzaLetta,ultimaTemperaturaLetta;
    boolean continuaLetturaForza, continuaLetturaTemperatura;
    boolean isReading = true;
    String LOG_CODE = "NOTIFSRV";
    GattClientCallback gattClientCallback;
    private static final int PERMISSION_REQUEST_COARSE_LOCATION = 1;


    public BlePowerService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        //throw new UnsupportedOperationException("Not yet implemented");
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mHandler = new Handler();

        Context sharedContext = null;
        try {
            sharedContext = this.createPackageContext(
                    "com.care.devicesensor",
                    Context.CONTEXT_INCLUDE_CODE);
            if (sharedContext == null) {
                return;
            }
            db=new DbLayer(sharedContext);
            db.open();
        } catch (Exception e) {
            String error = e.getMessage();
          //  Log.d(LOG_CODE,"DB error : " + error);
            return;
        }
    }


    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        try {
            //RECUPERO LE IMPOSTAZIONI SETTATE DALL'UTENTE
            settingApp = db.fetchSetting();
            if (settingApp != null && settingApp.getAddressBleSX()!=null) {
                //POSSO FILTRARE DIRETTAMENTE PER L'UUID DEL DISPOSITIVO MEMORIZZATO
                //DALL'UTENTE
                ScanFilter.Builder scanFilterMac =
                        null;
                    scanFilterMac = new ScanFilter.Builder().setDeviceAddress(settingApp.getAddressBleSX());
                if(filters==null)
                    filters = new ArrayList<ScanFilter>();
                //if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                filters.add(scanFilterMac.build());
                //}
                //FILTRO ANCHE PER LA CARATTERISTICA DI FORZA
                ScanFilter filter = null;
                    filter = new ScanFilter.Builder().setServiceUuid(ParcelUuid.fromString(CHARACTERISTIC_FORZA_STRING)).build();
                filters.add(filter);

                final BluetoothManager bluetoothManager =
                        (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
                    mBluetoothAdapter = bluetoothManager.getAdapter();
                //mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
                    mLEScanner = mBluetoothAdapter.getBluetoothLeScanner();
                    settings = new ScanSettings.Builder()
                            .setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)
                            .build();
                scanLeDevice(true);
                mTimer = new Timer();
                //ogni 2 ore
                continuaLetturaForza = true;
                continuaLetturaTemperatura = true;

                int nSecondi = settingApp.getFrequenzaDownload()!= null ? settingApp.getFrequenzaDownload() : 1;
                mTimer.schedule(timerTask, 10000, 1000 * nSecondi);
            }
        } catch (Exception e) {
           // Log.e("POWER_SERVICE", e.getMessage());
        }
        return super.onStartCommand(intent, flags, startId);
    }

    private Timer mTimer;

    TimerTask timerTask = new TimerTask() {

        @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
        @Override
        public void run() {
            //LEGGO TUTTI I DATI DAL SENSORE FINCHE CI SONO VALORI

            int counter = 0;
            while(continuaLetturaForza || continuaLetturaTemperatura){
                counter++;
                Log.v("CICLO WHILE", counter+"");
                if (currDevice != null) {

                    if(ReadQueue!= null && ReadQueue.size()>0){
                        int index =0;
                        for(index=0; index < ReadQueue.size(); index++){
                            isReading = mGatt.readCharacteristic(ReadQueue.get(index));
                            while(isReading){
                                try {
                                   Thread.sleep(1);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }

                        }
                    }

                }else{
                    //provo a ricollegarmi al dispositivo probabile, abbia perso la connessione con esso
                    scanLeDevice(true);
                    try {
                        Thread.sleep(2500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if(currDevice == null && counter == 25){
                        //in questo caso non è riuscito a trovare il dispositivo BLE
                        //esco dal ciclo
                        continuaLetturaForza = false;
                        continuaLetturaTemperatura = false;
                        continue;
                    }
                }

            }

            if(gattClientCallback!=null && mGatt != null)
                gattClientCallback.disconnectGattServer();
        }
    };


    public void connectToDevice(BluetoothDevice device) {
        //VERIFICO SE IL DEVICE è QUELLO CHE VOGLIO IO
        if (mGatt == null && settingApp != null
                && device.getAddress().equals(settingApp.getAddressBleSX())) {
            currDevice = device;
            gattClientCallback = new GattClientCallback();
            mGatt = currDevice.connectGatt(getBaseContext(), false, gattClientCallback);
            scanLeDevice(false);// will stop after first device detection
        }
    }

    private BluetoothAdapter.LeScanCallback mLeScanCallback =
            new BluetoothAdapter.LeScanCallback() {
                @Override
                public void onLeScan(final BluetoothDevice device, int rssi,
                                     byte[] scanRecord) {
                    Handler h = new Handler(getApplicationContext().getMainLooper());
                    // Although you need to pass an appropriate context
                    h.post(new Runnable() {
                        @Override
                        public void run() {
                          //  Log.i("onLeScan", device.toString());
                                connectToDevice(device);

                        }
                    });
                }
            };

    private void scanLeDevice(final boolean enable) {
        if (enable) {
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (Build.VERSION.SDK_INT < 21) {
                        mBluetoothAdapter.stopLeScan(mLeScanCallback);
                    } else {
                        mLEScanner.stopScan(mScanCallback);

                    }
                }
            }, SCAN_PERIOD);
            if (Build.VERSION.SDK_INT < 21) {
                mBluetoothAdapter.startLeScan(mLeScanCallback);
            } else {
                mLEScanner.startScan(filters, settings, mScanCallback);
            }
        } else {
            if (Build.VERSION.SDK_INT < 21) {
                mBluetoothAdapter.stopLeScan(mLeScanCallback);
            } else {
                mLEScanner.stopScan(mScanCallback);
            }
        }
    }


    private ScanCallback mScanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
           // Log.i("callbackType", String.valueOf(callbackType));
           // Log.i("result", result.toString());
            BluetoothDevice btDevice = null;
               btDevice = result.getDevice();
            connectToDevice(btDevice);
        }

        @Override
        public void onBatchScanResults(List<ScanResult> results) {
            for (ScanResult sr : results) {
                Log.i("ScanResult - Results", sr.toString());
            }
        }

        @Override
        public void onScanFailed(int errorCode) {
           Log.e("Scan Failed", "Error Code: " + errorCode);
        }
    };

    private class GattClientCallback extends BluetoothGattCallback {

        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            try{
                super.onConnectionStateChange(gatt, status, newState);
                Log.i("tag", "onConnectionStateChange newState: " + newState);

                if (status == BluetoothGatt.GATT_FAILURE) {
                    Log.e("ERROR_SERVICE", "Connection Gatt failure status " + status);
                    if(mGatt == null){

                    }else{
                        try {
                            gatt.close();
                        } catch (Exception e) {
                            Log.d("", "close ignoring: " + e);
                        }
                        mGatt = null;
                    }
                    return;
                } else if (status != BluetoothGatt.GATT_SUCCESS) {
                    // handle anything not SUCCESS as failure
                    Log.e("ERROR_SERVICE", "Connection not GATT sucess status " + status);
                    if(mGatt == null){

                    }else{
                        try {
                            gatt.close();
                        } catch (Exception e) {
                            Log.d("", "close ignoring: " + e);
                        }
                        mGatt = null;
                    }
                    return;
                }

                if (newState == BluetoothProfile.STATE_CONNECTED) {
                    //Log.i("INFO", "Connected to device " + gatt.getDevice().getAddress());
                    gatt.discoverServices();
                } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                    Log.i("INFO", "Disconnected from device");
                    if(mGatt == null){

                    }else{
                        try {
                            gatt.close();
                        } catch (Exception e) {
                            Log.d("", "close ignoring: " + e);
                        }
                        mGatt = null;
                    }

                }
            }catch(Exception e){
                Log.e("tag", e.getMessage());
                continuaLetturaForza = true;
                continuaLetturaTemperatura = true;
            }
        }

        public void disconnectGattServer() {
            //Log.i("INFo", "Closing Gatt connection");
            //  clearLogs();
            //mConnected = false;
            //mEchoInitialized = false;
            continuaLetturaForza = false;
            continuaLetturaTemperatura = false;
            if (mGatt == null) {

            }
            else{
                try{
                    mGatt.disconnect();
                   // mGatt.close();
                }catch(Exception e){
                    mGatt = null;
                }

            }
            //mGatt = null;
            //currDevice = null;
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            super.onServicesDiscovered(gatt, status);

            if (status != BluetoothGatt.GATT_SUCCESS) {
             //   Log.i("INFO", "Device service discovery unsuccessful, status " + status);
                return;
            }

            List<BluetoothGattCharacteristic> matchingCharacteristics =
                    BluetoothUtils.findCharacteristics(gatt,stringSequence);
            if (matchingCharacteristics.isEmpty()) {
              //  Log.e("ERROR_SERVICE","Unable to find characteristics.");
                return;
            }else {

                //INIZIALIZZO LA LISTA DI CARATTERISTICHE CHE DEVO ANDARE A LEGGERE
                ReadQueue = new ArrayList<>();
                for (BluetoothGattCharacteristic characterist : matchingCharacteristics) {
                    ReadQueue.add(characterist);
                }
            }



        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicRead(gatt, characteristic, status);
            if (status == BluetoothGatt.GATT_SUCCESS) {
                Log.v("INSERT_DB", "*****************************************");
                Log.v("INSERT_DB", "*****************************************");
                Log.v("INSERT_DB", "*****************************************");
                Log.v("INSERT_DB", "INSERISCO LE CARATTERISTICHE LETTE SUL DB");
                //readCharacteristic(characteristic);
                String valoreRestituito = characteristic.getStringValue(0);
                if(valoreRestituito==null){
                    int i = 0;
                    i = i + 1;
                    return;
                }
                //SPLITTO PER IL CARATTERE ;
                String[] arrayValori = valoreRestituito.split(SPLIT_CHAR);
                //1 valore è l ID
                try{
                    int id = new Integer(arrayValori[0]);
                    //VERIFICO SE STO LEGGENDO TEMPERATURA O FORZA
                    if(characteristic.getUuid().equals(CHARACTERISTIC_FORZA_UUID)){
                        Log.v("CARATTERISTICA", "*****************************************");
                        Log.v("FORZA", "*****************************************");
                        if(ultimaForzaLetta!= null && ultimaForzaLetta == id){
                            continuaLetturaForza = false;
                            isReading = false;
                            return;
                        }
                        ultimaForzaLetta = id;
                    }else if(characteristic.getUuid().equals( CHARACTERISTIC_TEMPERATURA_UUID)){
                        Log.v("CARATTERISTICA", "*****************************************");
                        Log.v("TEMPERATURA", "*****************************************");
                        if(ultimaTemperaturaLetta!= null && ultimaTemperaturaLetta == id){
                            continuaLetturaTemperatura = false;
                            isReading = false;
                            return;
                        }
                        ultimaTemperaturaLetta = id;
                    }

                    SensorData mSenData = new SensorData();
                    mSenData.setIdType(id);
                    mSenData.setValue1(arrayValori[1]);
                    mSenData.setValue2(arrayValori[2]);
                    mSenData.setValue3(arrayValori[3]);
                    mSenData.setValue4(arrayValori[4]);
                    mSenData.setValue5(arrayValori[5]);
                    mSenData.setValue6(arrayValori[6]);
                    mSenData.setValue7(arrayValori[7]);
                    mSenData.setValue8(arrayValori[8]);
                    //TO-DO HO COMMENTATO QUESTA RIGA DI CODICE
                    // mSenData.setIdType(st.getId());
                    mSenData.setCharacteristic(characteristic.getUuid().toString());
                    mSenData.setValueTimestamp(db.getDateTime(true));
                    //inserisco i dati nel db
                    Log.v("INSERT_DB",valoreRestituito);
                    Log.v("INSERT_DB", "*****************************************");
                    Log.v("INSERT_DB", "*****************************************");
                    Log.v("INSERT_DB", "*****************************************");
                    Log.v("INSERT_DB", "*****************************************");
                    Log.v("INSERT_DB", "*****************************************");
                    Log.v("INSERT_DB", "*****************************************");
                    Log.v("INSERT_DB", "FINE LE CARATTERISTICHE LETTE SUL DB");
                    db.insertSensorData(mSenData);

                    EventBus.getDefault().post(new MessageEvent("update"));

                    //EventBus.getDefault().post(new UnfriendEvent(userId));
                }catch (Exception e){
                    Log.e("ERROR", e.getMessage());
                }
                isReading = false;

            } else {
                isReading = false;
                Log.e("ERROR_SERVICE", "Characteristic read unsuccessful, status: " + status);
                Log.e("ERROR_SERVICE", "Characteristic read unsuccessful, status: " + status);
                Log.e("ERROR_SERVICE", "Characteristic read unsuccessful, status: " + status);
                Log.e("ERROR_SERVICE", "Characteristic read unsuccessful, status: " + status);
                Log.e("ERROR_SERVICE", "Characteristic read unsuccessful, status: " + status);
                Log.e("ERROR_SERVICE", "Characteristic read unsuccessful, status: " + status);
                Log.e("ERROR_SERVICE", "Characteristic read unsuccessful, status: " + status);
                Log.e("ERROR_SERVICE", "Characteristic read unsuccessful, status: " + status);
                Log.e("ERROR_SERVICE", "Characteristic read unsuccessful, status: " + status);

                // Trying to read from the Time Characteristic? It doesnt have the property or permissions
                // set to allow this. Normally this would be an error and you would want to:
                disconnectGattServer();

                return;
            }
        }
    }

    public void onDestroy() {
        try {
            db.close();
            Log.d(LOG_CODE,"DB connection closed" );

            mTimer.cancel();
            timerTask.cancel();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}

在 onStartCommand 方法中,我创建了一个 Timer,它每 X 次运行一次服务。

“cycle while”可以通过onCharacteristicRead方法下载BLE设备的所有信息。

现在的问题是,如果单元我可以读取一个特征,我关闭 BLE 设备,我可以通过 onConnectionStateChange 方法激活这个状态更改连接,但是 Timer 永远不会再次执行。

为什么计时器不再执行?

标签: androidbluetooth-lowenergy

解决方案


推荐阅读