gatt.writeCharacteristic() 可能返回 false 的原因是啥?
Posted
技术标签:
【中文标题】gatt.writeCharacteristic() 可能返回 false 的原因是啥?【英文标题】:What are the reasons why gatt.writeCharacteristic () could return false?gatt.writeCharacteristic() 可能返回 false 的原因是什么? 【发布时间】:2018-02-22 09:48:02 【问题描述】:我正在开发一个 android BLE 应用程序。在某些 Android 设备中,我面对的是,当我使用 writeCharacteristic() 方法在特征中写入数据时,它返回 false 并且不写入。 你知道什么情况下它会返回 false 吗? 使用我的 BQ Aquaris U Plus,它不会发生,只是写入成功并返回 true。但是对于我的华为 Y6,它发生了很多次。也许 7/10 的情况下它返回错误。 这是我的代码,很大但可以提供帮助:
public class ServicioFirmadoNuevo extends Service
private static final long NUMEROS_DE_RETRYS = Constantes.NUMEROS_DE_RETRYS;
private ServiceConnection serviceConn;
private ArrayList<byte[]> arrayDatosPartidos;
private Handler handler;
private BluetoothGatt mGatt;
private final IBinder mBinder = new ServicioFirmadoNuevo.LocalBinder();
private android.bluetooth.BluetoothDevice mBluetoothDevice;
private byte[] byteFinal;
private ArrayList<byte[]> datosAJuntar;
private int numeroDeParticionesDeDatos;
private boolean esperandoDesconexion = false;
private boolean protocoloLectura = false;
private boolean comunicacionTerminada = false;
private boolean retry = true;
private int contadorRetrys = 0;
private int iteracionesLectura = 0;
private String idMotivo;
private int vecesOnChanged = 0;
private int nSerie;
private Intent intentError = new Intent("errorFirmado");
public ServicioFirmadoNuevo()
@Override
public int onStartCommand(Intent intent, int flags, int startId)
return START_STICKY;
public void onStartCommand2(Intent intent, BluetoothDevice device, String motivoCodigo, String motivoLetra, int nserie)
Log.i("INICiosERVICIOFIRMADO", "TRUE");
mGatt = null;
handler = new Handler();
datosAJuntar = new ArrayList<byte[]>();
contadorRetrys = 0;
Log.d("pruebitas", motivoCodigo+motivoLetra);
mBluetoothDevice = device;
nSerie = nserie;
Log.d("NSERIEAFIRMAR", nserie+"");
/*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
if (device.getBondState() == BluetoothDevice.BOND_NONE)
Log.d("BOUNDING??? ", device.createBond()+"");
final String motCod = motivoCodigo;
new android.os.Handler().postDelayed(
new Runnable()
public void run()
conectaConEsteMotivo(motCod);
,
4000);*/
conectaConEsteMotivo(motivoCodigo);
public void setServiceConn(ServiceConnection serviceConn)
this.serviceConn = serviceConn;
public class LocalBinder extends Binder
public ServicioFirmadoNuevo getServiceInstance()
return ServicioFirmadoNuevo.this;
public void conectaConEsteMotivo(String idmotivo)
handler.postDelayed(timeOutFirmado, 10000);
handler.postDelayed(runnableCodeTimeOutConversacion, 9000);
this.idMotivo = idmotivo;
if (mGatt == null)
Log.e("mGATT", "IS NULL");
try
Handler mHandler = new Handler(getApplicationContext().getMainLooper());
mHandler.post(new Runnable()
@Override
public void run()
Log.e("TRY", "1");
if (mBluetoothDevice!=null)
/*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
Log.d("BOUNDING??? ", mBluetoothDevice.createBond()+"");
*/
Log.d("mBluetoothDevice", "mBluetoothDevice.connectGatt called...");
mGatt = mBluetoothDevice.connectGatt(getApplicationContext(), false, gattCallback);
/*new Handler().postDelayed(
new Runnable()
public void run()
Log.d("mBluetoothDevice", "mBluetoothDevice.connectGatt called...");
mGatt = mBluetoothDevice.connectGatt(getApplicationContext(), false, gattCallback);
,
1000);*/
);
catch (Throwable e)
e.printStackTrace();
if (mGatt != null)
mGatt.disconnect();
mGatt.close();
if (!retry)
Log.e("ERROR","ERROR");
//presenter.escribirEnToast("Problema Null Pointer en método : conectaConEsteMotivo(String a) ");
//presenter.pararServicioFirmado();
else
Log.i("MGATTISNOTNULL","MGATT NO ES NULL");
private Runnable runnableCodeTimeOutConversacion = new Runnable()
@Override
public void run()
//contadorRetrys = (int) NUMEROS_DE_RETRYS;
if (!esperandoDesconexion)
Log.e("TIMEOUTCONVERSACION", "TRUE");
if(mGatt != null)
mGatt.disconnect();
mGatt.close();
//presenter.escribirEnToast("TIMEOUT Conversación");
//presenter.setServicioEnEjecucion(false);
//presenter.pararServicioFirmado();
retrySameMotivo();
;
private final BluetoothGattCallback gattCallback = new BluetoothGattCallback()
@Override
public void onConnectionStateChange(final BluetoothGatt gatt, int status, int newState)
Log.i("onConnectionStateChange", "Status: " + status);
switch (newState)
case BluetoothProfile.STATE_CONNECTED:
Log.i("gattCallback", "STATE_CONNECTED");
boolean discover_services = gatt.discoverServices();
if (discover_services)
Log.i("Hadescubiertoservicios", "TRUE");
else
Log.i("Hadescubiertoservicios", "FALSE");
break;
case BluetoothProfile.STATE_DISCONNECTED:
Log.e("gattCallback", "STATE_DISCONNECTED STATUS: "+ status);
//gatt.disconnect();
//gatt.close();
//mGatt.disconnect();
//mGatt.close();
if(esperandoDesconexion)
if (mGatt != null)
mGatt.disconnect();
mGatt.close();
//presenter.setServicioEnEjecucion(false);
//presenter.pararServicioYReiniciar();
sendBroadcast(intentError);
else
if (idMotivo == null)
Log.e("ERRORIDMOTIVONULL", " IDMOTIVO ES NULL");
gatt.disconnect();
gatt.close();
if (mGatt != null)
mGatt.disconnect();
mGatt.close();
//presenter.escribirEnToast("IDMOTIVO ES NULL");
esperandoDesconexion = true;
sendBroadcast(intentError);
else
if(contadorRetrys < NUMEROS_DE_RETRYS )
retrySameMotivo();
else
Log.e("LimiteRetrysSuperado", " Ya se han hecho suficientes retrys y no se ha logrado firmar");
gatt.disconnect();
gatt.close();
if (mGatt != null)
mGatt.disconnect();
mGatt.close();
Log.e("retrys", "Límite Retrys alcanzado.");
//presenter.setServicioEnEjecucion(false);
//presenter.pararServicioYReiniciar();
esperandoDesconexion = true;
sendBroadcast(intentError);
break;
default:
Log.e("gattCallback", "STATE_OTHER");
@Override
public void onServicesDiscovered(final BluetoothGatt gatt, int status)
Log.i("onServicesDiscovered", "enter");
List<BluetoothGattService> services = gatt.getServices();
if (services.size() == 0)
Log.i("ServiciosDeLaBaliza=0","el sice de los servicios entontrados es = 0 :"+ services.toString());
Log.i("onServicesDiscovered", services.toString());
//Muestreo de Servicios con sus respectivas Characteristics
for (BluetoothGattService servicio : services)
Log.i("Service", servicio.getUuid().toString());
for (BluetoothGattCharacteristic characteristic : servicio.getCharacteristics())
Log.i("Char", characteristic.getUuid().toString());
Log.d("PASAMITADonSERVICEDISCD","-----");
try
BluetoothGattCharacteristic characteristic = gatt.getServices().get(2).getCharacteristics().get(0);//todo: CAMBIAR get 2 por su uuid
Log.d("CHARACTERISTIC -->", characteristic!= null ? "NO ES NULL": "ES NULL");
//habilitar notificaciones
gatt.setCharacteristicNotification(characteristic, true);
BluetoothGattDescriptor desc = characteristic.getDescriptors().get(0);
desc.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(desc);
catch (Exception e)
sendBroadcast(intentError);
e.printStackTrace();
Log.e("ERRORDESCUBRIENDO", "TRUE");
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status)
Log.e("ENTRA EN LEERCHAR", characteristic.getValue()[0]+"");
protocolo(gatt, characteristic);
//Cuando se escribe una caracteristica lanza esto
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status)
Log.e("ENTRAONWRITE", "STATUS: "+status);
if (status == BluetoothGatt.GATT_SUCCESS)
handler.postDelayed(runnableCodeTimeOutTransmisiones, 1000);
Log.i("ESCRIBIR","OK");
Log.i("bytesescritos", characteristic.getValue().length+""+ "////////"+ new String(characteristic.getValue(), Charset.forName("UTF-8")));
Log.i("1stEscrito", (char) characteristic.getValue()[0] + "");
if(new String(characteristic.getValue(), Charset.forName("UTF-8")).equals(Constantes.PM_END_ACK+""))
characteristic.setValue(Constantes.PM_END_COM+"");
boolean porcentaje;
porcentaje = gatt.writeCharacteristic(characteristic);
Log.w("LOQUEESCRIBO: ", BateriaDeMetodosUtiles.bytesToHex(characteristic.getValue())+ " : "+porcentaje);
Log.w("ESCPORCENT", porcentaje+"");
else
if (new String(characteristic.getValue(), Charset.forName("UTF-8")).equals(Constantes.PM_END_COM + ""))
byteFinal = BateriaDeMetodosUtiles.juntarBytesDeUnArrayListDeBytes(datosAJuntar);
Log.e("FINALBYTE", new String(byteFinal, Charset.forName("UTF-8")));
Log.e("FINALBYTEHEX", BateriaDeMetodosUtiles.bytesToHex(byteFinal));
protocoloLectura = false;
iteracionesLectura = 0;
esperandoDesconexion = true;
Log.e("VamosASalirDelProcess", "Deberíamos salir de la conexión al haber escrito esto: " + new String(characteristic.getValue(), Charset.forName("UTF-8")));
Intent intentBD = new Intent("fichajeCompletado");
Log.d("PRUEBABYTEEE", BateriaDeMetodosUtiles.bytesToHex(byteFinal));
intentBD.putExtra("byteFinal", byteFinal);
sendBroadcast(intentBD);
//presenter.pararServicioEscaneo();
if (vecesOnChanged == 2)
gatt.readCharacteristic(characteristic);
vecesOnChanged = 0;
else
Log.e("ESCRIBIRERROR","ERROR Lo que intentaste escribir era : "+characteristic.getValue() + "O en otras palabras: "+ BateriaDeMetodosUtiles.bytesToHex(characteristic.getValue())+" STATUS = "+status);
gatt.disconnect();
gatt.close();
if (mGatt != null)
mGatt.disconnect();
mGatt.close();
//presenter.escribirEnToast("ERROR ESCRIBIENDO");
Log.e("ERROR","ESCRIBIENDO");
sendBroadcast(intentError);
@Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status)
Log.i("onDescriptorWrite","enter");
byte[] paraLaBaliza ;//= BateriaDeMetodosUtiles.creacionDeRespuestaParaLaBaliza(idMotivo);
//nuevoMETODOO//////////
BaseDeDatos mBaseDeDatos = Room.databaseBuilder(getApplicationContext(), BaseDeDatos.class, Constantes.nombreBaseDeDatos).fallbackToDestructiveMigration().allowMainThreadQueries().build();
ControlHoras controlHoras = mBaseDeDatos.controlHorasDao().seleccionarTodasControlHoras();
paraLaBaliza = BateriaDeMetodosUtiles.creacionDeRespuestaParaBaliza2(idMotivo, controlHoras.getHoraPasada(), controlHoras.getHash(), controlHoras.getUpTimePasada(), nSerie);
Log.d("QUEENVIOBALIZA", ""+idMotivo);
//presenter.setFHDispositivo(BateriaDeMetodosUtiles.obtenerFH(paraLaBaliza)); LO HAGO CUANDO FICHO
Log.e("DatosQueRecibeBaliza", BateriaDeMetodosUtiles.bytesToHex(paraLaBaliza));
for (int i = 0; i < paraLaBaliza.length; i++)
Log.d("paraLabaliza", i+ " "+paraLaBaliza[i]);
ArrayList<byte[]> tmp = BateriaDeMetodosUtiles.particionDeBytes(paraLaBaliza);
arrayDatosPartidos = BateriaDeMetodosUtiles.creacionBytesDelProtocoloTam20(tmp);
Log.i("LENGTHESCRITURA", arrayDatosPartidos.get(0).length+"IS LEN");
numeroDeParticionesDeDatos = arrayDatosPartidos.size();
Log.i("DESCRIPTORWRITE","YES");
descriptor.getCharacteristic().setValue(Constantes.PM_START+"");
if ( gatt.writeCharacteristic( descriptor.getCharacteristic()) )
Log.i("ESCRIBECHARINONDESCRIPT","TRUE");
else
Log.i("ESCRIBECHARINONDESCRIPT","FALSE");
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic)
Log.i("onCharacteristicChanger", "enter");
vecesOnChanged++;
char charrr = (char) characteristic.getValue()[0];
Log.e("QUEESCHANGE1st", charrr+"");
if (vecesOnChanged == 2 && charrr == '$')
Log.e("RESTAONCHANGE","TRUE");
vecesOnChanged --;
byte[] valorCambiado = characteristic.getValue();
Log.i("CHANGED", "TRUE");
Log.i("itera", iteracionesLectura+"");
Log.i("VALORCHANGED",new String(characteristic.getValue(), Charset.forName("UTF-8")));
Log.i("VALORCHANGEDLEN",characteristic.getValue().length+"");
if ((!protocoloLectura) || (protocoloLectura && (valorCambiado[0] != Constantes.PM_ACK)))
Log.d("C_PROTOCOLO_ON_CHANGED", "TRUE");
protocolo(gatt, characteristic);
;
private void protocolo(final BluetoothGatt gatt, BluetoothGattCharacteristic characteristic)
Log.w("ENTRAPROTOCOLO", "TRUE");
try
handler.removeCallbacks(runnableCodeTimeOutTransmisiones);
catch (NullPointerException e)
e.printStackTrace();
byte[] valorLeido = characteristic.getValue();
Log.i("Lectura: ", new String(characteristic.getValue(), Charset.forName("UTF-8")));
String resultadoLegible = "";
for (int i = 0; i < valorLeido.length; i++)
resultadoLegible += valorLeido[i] +"";
//Log.i("Legible", resultadoLegible);
String valorEnHex = BateriaDeMetodosUtiles.bytesToHex(valorLeido);
Log.i("VALORREADED:",resultadoLegible);
Log.i("VALORHEX", valorEnHex);
Log.i("ValorString", new String (characteristic.getValue(),Charset.forName("UTF-8")));
Log.i("VALORLENGTH:",""+characteristic.getValue().length);
if (iteracionesLectura <= numeroDeParticionesDeDatos) // es menor o igual porque la primera vez lees solo para empezar la comunicacion, si no sería menor estrícto
if(valorLeido[0] == Constantes.PM_ACK)
if (iteracionesLectura == numeroDeParticionesDeDatos)
Log.i("ESCRIBODESPEDIDA","TRUE");
characteristic.setValue(Constantes.PM_END+"");
else
Log.i("LENGTHESCRITURA", arrayDatosPartidos.get(iteracionesLectura).length+"IS LEN");
characteristic.setValue(arrayDatosPartidos.get(iteracionesLectura));
Log.e("LENGTHCHARESCRI", characteristic.getValue().length+"");
boolean porcentaje;
porcentaje = gatt.writeCharacteristic(characteristic);
Log.w("LOQUEESCRIBO: ", BateriaDeMetodosUtiles.bytesToHex(characteristic.getValue())+ " : "+porcentaje);
iteracionesLectura++;
else
Log.e("ERRORHEADER","no me ha devuelto un +");
//gatt.disconnect();
//gatt.close();
//mGatt = null;
iteracionesLectura = 0;
sendBroadcast(intentError);
else
protocoloLectura = true;
if(!comunicacionTerminada)
if(valorLeido[0] != Constantes.PM_END_ACK)
if (valorLeido[0] == Constantes.PM_START)
characteristic.setValue(Constantes.PM_ACK+"");
boolean porcentaje;
porcentaje = gatt.writeCharacteristic(characteristic);
Log.w("LOQUEESCRIBO: ", BateriaDeMetodosUtiles.bytesToHex(characteristic.getValue())+ " : "+porcentaje);
else if (valorLeido[0] == Constantes.PM_END)
characteristic.setValue(Constantes.PM_END_ACK+"");
boolean porcentaje;
porcentaje = gatt.writeCharacteristic(characteristic);
Log.w("LOQUEESCRIBO: ", BateriaDeMetodosUtiles.bytesToHex(characteristic.getValue())+ " : "+porcentaje);
else
if (valorLeido[1] > 0 && valorLeido[1] <= 18)
datosAJuntar.add(BateriaDeMetodosUtiles.addByteAlArrayFinal(valorLeido));//almaceno en un arrayList todos los datos que leo para después juntarlo.
characteristic.setValue(Constantes.PM_ACK+"");
boolean porcentaje;
porcentaje = gatt.writeCharacteristic(characteristic);
Log.w("LOQUEESCRIBO: ", BateriaDeMetodosUtiles.bytesToHex(characteristic.getValue())+ " : "+porcentaje);
else
//presenter.escribirEnToast("Valor leído en el Value de la Característica: " + new String(characteristic.getValue(), Charset.forName("UTF-8")));
//gatt.disconnect();
//gatt.close();
//mGatt = null;
iteracionesLectura = 0;
retry = false;
Log.i("Comunicacion terminada", "TRUE");
private void retrySameMotivo()
contadorRetrys++;
Log.e("RetryMOTIVOSAME", "TRUE");
//mGatt = null;
try
mGatt.disconnect();
mGatt.close();
conectaConEsteMotivoRetry(idMotivo);
catch (NullPointerException e)
e.printStackTrace();
sendBroadcast(intentError);
public void conectaConEsteMotivoRetry(String idmotivo)
this.idMotivo = idmotivo;
handler.removeCallbacks(runnableCodeTimeOutConversacion);
//handler.postDelayed(timeOutFirmado, 10000);
if (mGatt != null)
try
//myTimerProtocolo = null;
handler.removeCallbacks(runnableCodeTimeOutTransmisiones);
Log.d("mBluetoothDevice", "mBluetoothDevice.connectGatt called in the retry...");
/*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
Log.d("BOUNDING??? ", mBluetoothDevice.createBond()+"");
*/
mGatt = mBluetoothDevice.connectGatt(getApplicationContext(), false, gattCallback);
//stopScan();// will stop after first device detection
catch (NullPointerException e)
e.printStackTrace();
else
Log.i("MGATTISNULL","MGATT ES NULL");
private Runnable runnableCodeTimeOutTransmisiones = new Runnable()
@Override
public void run()
if (!esperandoDesconexion)
//contadorRetrys = (int) NUMEROS_DE_RETRYS;
try
Log.e("TIMERPROTOCOLO", "TRUE");
if(mGatt!= null)
mGatt.disconnect();
mGatt.close();
if (!retry)
Log.e("TIMEOUT","TRANSMISIONES");
// presenter.escribirEnToast("TIMEOUT Transmisiones");
sendBroadcast(intentError);
/*else
retrySameMotivo();
*/
catch (NullPointerException e)
e.printStackTrace();
;
private Runnable timeOutFirmado = new Runnable()
@Override
public void run()
try
Log.e("TIMEOUTGLOBALMAXFIRMADO", "TRUE");
//presenter.escribirEnToast("TIMEOUT Global FIRMANDO");
//PRUEBA LISTASCAN
sendBroadcast(intentError);
mGatt.disconnect();
mGatt.close();
catch (Exception e)
e.printStackTrace();
try
Log.e("HACER DESCONAMANO","TRUE");
mGatt.disconnect();
mGatt.close();
catch (Exception exc)
exc.printStackTrace();
;
@Nullable
@Override
public IBinder onBind(Intent intent)
return mBinder;
@Override
public boolean onUnbind(Intent intent)
try
mGatt.disconnect();
mGatt.close();
Log.e("UNBINDFirmado", "UNBIND");
//presenter.lanzarServicioFirmado();
try
handler.removeCallbacks(runnableCodeTimeOutTransmisiones);
handler.removeCallbacks(runnableCodeTimeOutConversacion);
handler.removeCallbacks(timeOutFirmado);
/*if (presenter.getErrorFirmando() && presenter.getNumeroIntentosFirmar() <= 2)
presenter.setNumeroIntentosFirmar(presenter.getNumeroIntentosFirmar() + 1);
presenter.setFlagScanDevice(true);
presenter.escribirEnToast("Reintento...");
presenter.connectToDeviceServicio(presenter.getActualDevice(), presenter.getNserieString());
else
presenter.setNumeroIntentosFirmar(0);
//presenter.desaparecerBotonesMotivos();
presenter.setVisibilityMensajeDespuesDeFirmar(View.VISIBLE);
presenter.setVisibilityBotonAceptarDespuesDeFirmar(View.VISIBLE);
presenter.setIconFirmadoEstado(R.drawable.check_gif);
if(presenter.getTextDespuesFirmado().equals("Ha ocurrido un problema con su fichaje, vuelva a intentarlo."))
presenter.setVisibilityBotonReintentar(View.VISIBLE);
*/
catch (NullPointerException e)
Log.e("ERROR IN UNBIND", "A NULLPOINT");
e.printStackTrace();
catch (Exception e)
e.printStackTrace();
return super.onUnbind(intent);
【问题讨论】:
您的代码中有几个 writeCharacteristic 调用。是每次调用都会返回 false 还是只有部分调用返回 false? 我在完全阅读长(和西班牙语)代码时遇到了一些麻烦,但是用 Notification 属性写入特征对我来说看起来很奇怪,尽管理论上它可能会发生。 抱歉演示文稿。我使用通知来进行回调。 第一次写返回true但没有调用onWriteCharacteristic回调,第二次写,write方法返回false,这次调用回调! 【参考方案1】:它可能会返回 false,因为在 BLE 中您一次可以执行一项操作。如果您同时执行多个写入,则它只执行最后一次写入。
所以,你必须等到一个写完,然后你才能写另一个。
【讨论】:
有道理,但我一直在确保我不会同时写两次.. 我只是为了发布它! 常见的要求是一次只能执行一个操作,并且特征属性必须是可写的。以上是关于gatt.writeCharacteristic() 可能返回 false 的原因是啥?的主要内容,如果未能解决你的问题,请参考以下文章